搞一个网站要多少钱,企业所得税税收优惠,骄阳房地产网站,网站登录界面用什么软件做文章目录 协程切换方案协程库的完善程度协程栈方案协程调度实现有栈协程与无栈协程对称协程与非对称协程 协程切换方案 具体使用和解析看栈切换那个博客 使用setjump、longjump c语言提供的方案 可参考#xff1a;libmill 使用操作系统提供的api#xff1a;ucontext、fiber … 文章目录 协程切换方案协程库的完善程度协程栈方案协程调度实现有栈协程与无栈协程对称协程与非对称协程 协程切换方案 具体使用和解析看栈切换那个博客 使用setjump、longjump c语言提供的方案 可参考libmill 使用操作系统提供的apiucontext、fiber 这种方式是最安全可靠的但是性能比较差。 可参考libtask 自己写汇编码实现 这种方式的性能可以很好但是不同系统、甚至不同版本的linux都需要不同的汇编码兼容性奇差无比。 可参考libco 使用boost coroutine、context等性能很好boost也帮忙处理了各种平台架构的兼容性问题不过需要依赖boost框架。 可参考libgo
协程库的完善程度 API级 实现协程上下文切换api或添加一些便于使用的封装。 如boost.context, boost.coroutine 问题没有协程调度 玩具级 实现了协程调度无需用户手动处理协程上下文切换。 如libmill 问题没有HOOK只实现了一套网络io相关函数这也意味着涉及网络的第三方库全部不可用了。 工业级 以部分正确的方式HOOK了网络io相关的syscall可以少改甚至不改代码的兼容大多数第三方库。 如libco 问题没有完整生态协程间通讯、协程同步、调试等机制不够完善。未能完全模拟syscall的行为只能兼容行为符合预想的同步模型的第三方库只能覆盖一部分的第三方库。 框架级 以100%行为模拟的方式HOOK了网络io相关的syscall可以完全不改代码兼容大多数第三方库。 如libgo 问题由于C的灵活性用户行为是不受限的所以依然存在几个边边角角的难点需要开发者注意没有gcTLS的问题用户不按套路出牌、把逻辑代码run在协程之外粗粒度的线程锁等等。 语言级 语言级的协程实现 如golang 开发者的一切行为都是受限行为可以实现无死角的完善的协程。 c20也支持协程了
协程栈方案 静态栈 栈大小固定有大小难以权衡的问题。 设置大了会造成浪费。 设置小了会有栈溢出问题。 分段栈 GCC支持一种允许栈内存不连续的编译参数实现原理是在每个函数调用开头都插入一段栈内存检测的代码如果栈内存不够用了就申请一块新的内存作为栈内存的延续。 但是第三方库没有使用这种方式来编译那就无法在其中检测栈内存是否需要扩展栈溢出的风险很大。 拷贝栈 每次检测到栈内存不够用时申请一块更大的新内存将现有的栈内存copy过去就像std::vector那样扩展内存。 但C/C是有指针的栈内存的copy会导致指向其内存地址的指针失效又因为其指针的灵活性修改对应的指针成为了一种几乎不可能实现的事情。 共享栈libco 申请一块大内存作为共享栈比如8MB每次协程挂起时计算协程栈真正使用的内存copy到私有栈中唤醒协程时把协程私有栈的内存copy到共享栈中这样每次只需保存真正使用到的栈内存量即可。 这种方案极大程度上避免了内存的浪费做到了用多少占多少同等内存条件下可以启动的协程数量更多但是协程切换慢还有引用失效问题。 虚拟内存栈libgo 申请的内存并不会立即被映射成物理内存而是仅管理于虚拟内存中真正对其读写时才会触发缺页中断分配物理内存而且基本上是按页递增分配。
协程调度实现 栈式调度libco 栈式调度是典型的不公平调度。协程队列是一个栈式的结构每次创建的协程都置于栈顶并且会立即暂停当前协程并切换至子协程中运行子协程运行结束或其他原因导致切换出来后继续切换回来执行父协程越是处于栈底部的协程越早创建的协程被调度到的机会就越少。 星切调度libgo 调度线程 - 协程A - 调度线程 - 协程B - 调度线程 - … 调度线程居中协程在周围调度顺序图看起来就像是星星一样称为星切。 将当前可调度的协程组织成先进先出的队列runnable list顺序pop出来做调度新创建的协程排入队尾调度一次后如果状态依然是可调度runnable的协程则排入队尾调度一次后如果状态变为阻塞那阻塞事件触发后也一样排入队尾是为公平调度。 环切调度 调度线程 - 协程A - 协程B - 协程C - 调度线程 - … 调度线程居中协程在周围调度顺序图看起来呈环状称为环切。 为了突破传统协程库仅用来处理I/O密集型业务的局限也能适用于CPU密集型业务可充当并行编程库来使用。
有栈协程与无栈协程
所谓的有栈无栈并不是说这个协程运行的时候有没有栈。
有栈协程是真的给你开了一个栈如golang主流的无栈协程方案例如CRust等是把一个协程函数编译成状态机的逻辑然后用一块临时分配的堆内存去保存这个函数里的变量和协程状态机以及上下文等内容。
无栈不管从效率内存占用看当然是更优的方案但是无栈需要编译器支持有栈只需要编写同一套上下文切换的代码。移植到有栈协程上比无栈也要相对简单现在主流的无栈协程基本都需要进行侵入式的修改。
使用上最大的区别就是协程是否可以在其任意嵌套函数中被挂起有栈协程是可以的而无栈协程则不可以。
有栈协程
每个协程有单独的上下文可以在任意的嵌套函数中任何地方挂起此协程不需要编译器做语法支持通过汇编指令即可实现需要提前分配一定大小的堆内存保存每个协程上下文所以会出现内存浪费或者栈溢出上下文拷贝和切换成本高性能低于无栈协程
无栈协程
不需要为每个协程保存单独的上下文内存占用低切换成本低性能更高需要编译器提供语义支持只能在这个生成器内挂起此协程无法在嵌套函数中挂起此协程异步代码必须都有对应的关键字
对称协程与非对称协程
对称协程 Symmetric Coroutine任何一个协程都是相互独立且平等的调度权可以在任意协程之间转移。非对称协程 Asymmetric Coroutine协程出让调度权的目标只能是它的调用者即协程之间存在调用和被调用关系。
对称协程提供了更高的并发性和灵活性适合需要高并发处理的场景而非对称协程则在某些控制流固定的场景下更为适用。