协程和线程是不同层面上的东西!某种程度上,协程和线程的差异,比线程和进程的差异还要大!
在更大程度上,协程和线程是互补的关系,而不是竞争的关系!
协程和线程最主要的差异是:线程是抢占式调度的,协程是"协作式"调度的
- 如果一个线程捣蛋(例如
while(1){}
),一般不影响其它线程(占了锁就另说) - 如果协程也这样捣蛋,同一线程中的其它协程一起完蛋
- 线程的调度是操作系统全权处理的,协程的调度是用户代码全权处理,所以协程的调度效率要高得多
- 权力越大,责任越大,特别是在“调度”上
- 操作系统的线程调度是久经考验的,其稳定性、可靠性、适用性是有保证的
- 协程的调度策略一般比较粗糙,大多数情况下仅限于封闭环境下的特殊场景
- 要把协程的应用场景无限扩大化,其调度策略就必须考虑“通用性”,从而会降低性能,失去效率优势,最典型的例如很多协程库鼓吹自己的“跨线程迁移”功能,捡了芝麻,丢了西瓜
在 大道至简,事半功倍:MultiGet IO 并发在 ToplingDB 中的协程实现,以及在 MyTopling 中的落地应用 中,我们使用了 boost fiber(协程),它的调度就过于越俎代庖,为了支持跨线程迁移,协程调度中就会不可避免地使用 lock,在火焰图中,我们可以清楚地看到这一点:

蓝框中的部分,就是协程的调度开销,看似占比不大,但是这些消耗完全是不必要的,如果舍弃那些不必要的功能,这部分消耗至少可以降低 90%。
boost 文档中讲到,通过定义 BOOST_FIBERS_NO_ATOMICS,可以消除这些不必要的消耗,然而,直到现在(2022-09-16),这个宏仍然只是个摆设:build failed with cxxflags -D BOOST_FIBERS_NO_ATOMICS,并且这个问题有人在一年前就提了:BOOST_FIBERS_NO_ATOMICS compile error。
我当然不可能因为这个问题就自己去实现一个完整的 fiber 库,但是,我仍然对 boost fiber 库做了一个小的外科手术(参考 boost-fiber-leipeng (github.com)),大幅降低了协程调度的开销(前面的火焰图已经包含了这个改进)。
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
不要在偶尔的努力中感动自己,也不要在适度放松时有自责的情绪。当你认识到,只有持续性的努力和进步,才会让自己越变越好时,你也就有了坚持的动力。
10月前

评论