资讯专栏INFORMATION COLUMN

Swoole协程之旅-前篇

terasum / 1762人阅读

摘要:协程完全有用户态程序控制,所以也被成为用户态的线程。目前支持协程的语言有很多,例如等。协程之旅前篇结束,下一篇文章我们将深入分析原生协程部分的实现。

写在最前

  Swoole协程经历了几个里程碑,我们需要在前进的道路上不断总结与回顾自己的发展历程,正所谓温故而知新,本系列文章将分为协程之旅前、中、后三篇。

前篇主要介绍协程的概念和Swoole几个版本协程实现的主要方案技术;

中篇主要深入Zend分析PHP部分的原理和实现;

后篇主要补充和分析协程4.x的实现。

软文正式开始 协程是什么?

  概念其实很早就出现了,摘wiki一段:According to Donald Knuth, the term coroutine was coined by Melvin Conway in 1958, after he applied it to construction of an assembly program.The first published explanation of the coroutine appeared later, in 1963. 协程要比c语言的历史还要悠久,究其概念,协程是子程序的一种, 可以通过yield的方式转移程序控制权,协程之间不是调用者与被调用者的关系,而是彼此对称、平等的。协程完全有用户态程序控制,所以也被成为用户态的线程。协程由用户以非抢占的方式调度,而不是操作系统。正因为如此,没有系统调度上下文切换的开销,协程有了轻量,高效,快速等特点。(大部分为非抢占式,但是,比如golang在1.4也加入了抢占式调度,其中一个协程发生死循环,不至于其他协程被饿死。需要在必要的时刻让出CPU,Swoole在V4.3.2增加了这个特性)。

  协程近几年如此火爆,很大一部分原因归功与golang在中国的流行和快速发展,受到很多开发的喜爱。目前支持协程的语言有很多,例如: golang、lua、python、c#、javascript等。大家也可以用很短的代码用c/c++撸出协程的模型。当然PHP也有自己的协程实现,也就是生成器,我们这里不展开讨论。

Swoole1.x

   Swoole最初以高性能网络通讯引擎的姿态进入大家视线,Swoole1.x的编码主要是异步回调的方式,虽然性能非常高效,但很多开发都会发现,随着项目工程的复杂程度增加,以异步回调的方式写业务代码是和人类正常思维相悖的,尤其是回调嵌套多层的时候,不仅开发维护成本指数级上升,而且出错的几率也大幅增加。大家理想的编码方式是:同步编码得到异步非阻塞的性能。所以Swoole很早的时候就开始了协程的探索。

  最初的协程版本是基于PHP生成器GeneratorsYield的方式实现的,可以参考PHP大神Nikita的早期博客的关于协程介绍。PHP和Swoole的事件驱动的结合可以参考腾讯出团队开源的TSF框架,我们也在很多生产项目中使用了该框架,确实让大家感受到了,以同步编程的方式写异步代码的快感,然而,现实总是很残酷,这种方式有几个致命的缺点:

所有主动让出的逻辑都需要yield关键字。这会给程序员带来极大的概率犯错,导致大家对协程的理解转移到了对Generators语法的原理的理解。

由于语法无法兼容老的项目,改造老的项目工程复杂度巨大,成本太高。

这样使得无论新老项目,使用都无法得心应手。

Swoole2.x

   2.x之后的协程都是基于内核原生的协程,无需yield关键字。2.0的版本是一个非常重要的里程碑,实现了php的栈管理,深入zend内核在协程创建,切换以及结束的时候操作PHP栈。在Swoole的文档中也介绍了很多关于每个版本实现的细节,我们这篇文章只对每个版本的协程驱动技术做简单介绍。原生协程都有对php栈的管理,后续我们会多带带拿一片文章来深入分析PHP栈的管理和切换。

   2.x主要使用了setjmp/longjmp的方式实现协程,很多C项目主要采用这种方式实现try-catch-finally,大家也可以参考Zend内核的用法。setjmp的首次调用返回值是0,longjmp跳转时,setjmp的返回值是传给longjmp的value。 setjmp/longjmp由于只有控制流跳转的能力。虽然可以还原PC和栈指针,但是无法还原栈帧,因此会出现很多问题。比如longjmp的时候,setjmp的作用域已经退出,当时的栈帧已经销毁。这时就会出现未定义行为。假设有这样一个调用链:

func0() -> func1() -> ... -> funcN()

只有在func{i}()中setjmp,在func{i+k}()中longjmp的情况下,程序的行为才是可预期的。

Swoole3.x

3.x是生命周期很短的一个版本,主要借鉴了fiber-ext项目,使用了PHP7的VM interrupts机制,该机制可以在vm中设置标记位,在执行一些指令的时候(例如:跳转和函数调用等)检查标记位,如果命中就可以执行相应的hook函数来切换vm的栈,进而实现协程。虽然我们完整的实现了协程的功能,但是由于并没有相对2.x有很大的进步,原因我们后续的文章会做进一步分析,所以我们放弃了这个版本,直接进入了4.x的版本迭代。

Swoole4.x

4.x协程是当前Swoole的协程版本,借鉴了前面版本的缺点和问题,引入了PHP+C双栈管理维护,完美的支持PHP各种语法,详细分析我们放在系列文章最后。

End

协程之旅前篇结束,下一篇文章我们将深入Zend分析Swoole原生协程PHP部分的实现。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/31278.html

相关文章

  • Swoole 在 Swoft 中的应用

    摘要:在中的应用官网源码解读号外号外欢迎大家我们开发组定了一个就线下聚一次的小目标上一篇源码解读反响还不错不少同学推荐再加一篇讲解一下中使用到的功能帮助大家开启的实战之旅服务器开发涉及到的相关技术领域的知识非常多不日积月累打好基础是很难真正 date: 2017-12-14 21:34:51title: swoole 在 swoft 中的应用 swoft 官网: https://www.sw...

    EscapedDog 评论0 收藏0
  • Swoole 4.4 协程抢占式调度器详解

    摘要:抢占式调度我们在今年年初就计划实现的抢占式调度,以满足实现有些场景下的不均衡调度带来的问题。考虑开线程,负责检查当前执行协程执行时间。达到我们的第二个协程主动抢占第一个协程的效果。 前言 Swoole内核团队开设的专栏,会逐渐投入精力写文章介绍Swoole的开发历程,实现原理,应用实践等,大家可以更好的交流,共同学习,建设PHP生态。 协程调度 去年Swoole推出了4.0版本后,完整...

    Bowman_han 评论0 收藏0
  • 【宇润日常疯测-007】Swoole 协程与传统 fpm 同步模式比较

    摘要:初识协程执行结果协程与同步模式比较我们一直在说协程适合用于密集场景,在同样的硬件配置环境下,它会比传统的同步模式承载更多的访问量。假设一次查询为,在传统同步模式下,当前进程在这的时间里,是不能做其它操作的。同步模式,耗费左右的是。 如果说数组是 PHP 的精髓,数组玩得不6的,根本不能算是会用PHP。那协程对于 Swoole 也是同理,不理解协程去用 Swoole,那就是在瞎用。 首先...

    henry14 评论0 收藏0
  • 现有PHP项目引入Swoole4协程支持的流程及难点

    摘要:之后协程化支持已经完善并且支持大量的扩展自动协程化一些基于的框架也蓬勃发展光看着文档就让人跃跃欲试但是对于现有旧项目如何引入并启用协程成了实际场景中的客观问题由于协程性质及生命周期等原因这并非想象的那么容易本文整理了在现有项目中引入并开启协 Swoole4之后,协程化支持已经完善,并且支持大量的PHP扩展自动协程化.一些基于Swoole4的框架也蓬勃发展,光看着文档就让人跃跃欲试.但是...

    高胜山 评论0 收藏0
  • PHP 协程:Go + Chan + Defer

    摘要:为语言提供了强大的协程编程模式。提供的协程语法借鉴自,在此向开发组致敬协程可以与很好地互补。并发执行使用创建协程,可以让和两个函数变成并发执行。协程需要拿到请求的结果。 Swoole4为PHP语言提供了强大的CSP协程编程模式。底层提供了3个关键词,可以方便地实现各类功能。 Swoole4提供的PHP协程语法借鉴自Golang,在此向GO开发组致敬 PHP+Swoole协程可以与...

    nidaye 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<