保护私人版权,尊重他人版权。转载请注明出处并附带页面链接
什么是协程
协程这个概念很早就被提出来了,只是最近几年逐渐开始在各个语言中得到广泛应用,如Python、Golang、Lua等。我们先来说一下进程,一开始我们想同时运行多个程序,每个程序有自己的内存互不干扰,于是就抽象出了进程的概念,通过虚拟内存、进程表之类的东西来管理多个程序的运行。但是有时候单个程序内可能遇到I/O阻塞,如果都通过多进程去解决开销会很大,因为操作系统切换进程代价是比较大的,所以就有了线程,线程不需要切换页表之类的,切换线程的代价比进程要小。而协程则是在线程之内的概念,我们不需要由操作系统去切换进程或者线程,而是由自己去实现一个逻辑流调度的东西,协程的本质是用户空间下的线程。
说了这么多,我觉得最简单的理解就是为了制造一个可以随时中断、随时恢复的函数。
协程的好处有什么:
- 不需要陷入内核做线程切换,而是在用户空间内切换上下文,从而减少了CPU的消耗
- 可以用同步的方式去写异步代码
生成器
首先我们来认识一下PHP中的生成器。
生成器类
1 | Generator implements Iterator { |
迭代生成器
假如我们现在有一个需求,打印1到100万之间的整数,普通的写法如下
1 | foreach (range(1, 1000000) as $num) { |
显然这样会在内存中存储100万个整数,而通过生成器去实现这个需求可以不用一次性的将这些数字加载到内存中
1 | function xrange($start, $end, $step = 1) |
生成器为可中断的函数
要从生成器认识协程,理解它内部是如何工作是非常重要的:生成器是一种可中断的函数,在它里面的yield构成了中断点,下面通过rewind、next、current方法演示一下手动调用生成器:
1 | function xrange($start, $end, $step = 1) |
输出:
1 | int(1) |
协程
协程的支持是在迭代生成器的基础上,增加了可以回送数据给生成器的功能(调用者发送数据给被调用的生成器函数)),这就把生成器到调用者的单向通信转变为两者之间的双向通信。
传递数据的功能是通过迭代器的send方法实现的。
1 | function gen() |
输出如下:
1 | string(6) "yield1" // 由var_dump($gen->current())输出 |
结语
本文只是对PHP中的协程实现作了简单的介绍,如果你有用过其它语言的协程,相信理解起来并不难。如果想要有更多的了解,可以参看以下文章: