您的位置 首页 php

「服务器」协程探秘,你知多少

协程不是进程或 线程 ,其执行过程更类似于子例程,或者说不带返回值的函数调用。在所有语言中子程序都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。所以 子程序 调用是通过栈实现的,一个线程就是执行一个子程序。

子程序调用总是一个入口,一次返回,调用顺序是明确的,而协程的调用和子程序不同。协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行,而协程却可以进入多次并返回多次。

上图中的程序,如果是一个子程序,那么它只能把 1、2、3 依次执行后,才返回。如果是协程,它可能在 1 处暂停,然后在某个时刻从 2 处继续执行;接着在 2 处执行完之后暂停,然后在另外一个时刻从 3 处继续执行。

协程虽然是一个线程执行,但和 多线程 相比,其最大的优势就是极高的执行效率。子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

另外,协程不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

使用PHP实现协程

从PHP5.5开始,php开始了对迭代(生成)器和协程的支持。对协程的支持是在迭代生成器的基础上,增加了可以回送数据给生成器的功能(调用者发送数据给被调用的生成器函数),这就把生成器到调用者的单向通信转变为两者之间的双向通信。如:

示例代码

那么什么是迭代(生成)器呢?

迭代(生成)器也是一个函数,不同的是这个函数的返回值是依次返回,而不是只返回一个单独的值。

下面通过实现一个xrange函数来简单说明:

示例代码

上面这个xrange()函数提供了和PHP的内建函数range()一样的功能,但是不同的是range()函数返回的是一个包含值从1到100万的数组, 而xrange()函数返回的是依次输出这些值的一个 迭代器 , 而不会真正以数组形式返回。这种方法的优点是显而易见的,它可以让你在处理大数据集合的时候不用一次性的加载到内存中,甚至你可以处理无限大的数据流。当然,也可以不用通过迭代生成器来实现这个功能,而是可以通过继承 Iterator 接口实现。但通过使用迭代生成器实现起来会更方便,不用再去实现iterator接口中的5个方法了。

要从迭代生成器认识协程,理解它内部是如何工作是非常重要的。 迭代生成器是一种可中断的函数,在它里面的yield构成了中断点。还是看上面的例子,调用xrange(1,1000000)的时候, xrange()函数里代码其实并没有真正地运行,它只是返回了一个迭代器。如下图:

示例代码

这就解释了为什么xrange()叫做迭代生成器, 因为它返回一个迭代器, 而这个迭代器实现了Iterator接口。调用迭代器的方法一次, 其中的代码运行一次。

例如, 如果你调用$range->rewind(), 那么xrange()里的代码就会运行到控制流第一次出现yield的地方。而函数内传递给yield语句的返回值可以通过$range->current()获取。为了继续执行跌代生成器中yield后的代码, 你就需要调用$range->next()方法。这将再次启动生成器, 直到下一次yield语句出现。因此,连续调用next()和current()方法,你就能从生成器里获得所有的值,直到再没有yield语句出现。

对xrange()来说,这种情形出现在$i超过$end时,在这种情况下,控制流将到达函数的终点,因此将不执行任何代码。一旦这种情况发生,vaild()方法将返回假,这时迭代结束。

下图是使用PHP实现协程的一个案例:

示例代码

使用 Swoole 实现协程

Swoole在2.0开始内置协程(Coroutine)的能力,提供了具备协程能力IO接口(统一在命名空间Swoole\Coroutine\*)。Swoole可以为每一个请求创建对应的协程,然后根据IO的状态来合理的调度协程。

Swoole这种模式带来了以下优势:

  1. 开发者可以无感知的用同步的代码编写方式达到异步IO的效果和性能,避免了传统异步回调所带来的离散的代码逻辑和陷入多层回调中导致代码无法维护。

  2. 同时由于swoole是在底层封装了协程,所以对比传统的php层协程框架,开发者不需要使用yield关键词来标识一个协程IO操作,不再需要对yield的语义进行深入理解以及对每一级的调用都修改为yield,这极大的提高了开发效率。

Swoole现实协程的案例如下:

当代码执行到 connect ()和recv()函数时,swoole会触发进行协程切换,此时swoole可以去处理其他的事件或者接受新的请求。当此client连接成功或者后端服务回包后,swoole server会恢复协程上下文,代码逻辑继续从切换点开始恢复执行。整个过程不需要开发者去干预。

当然,Swoole实现协程不仅仅如上面所示方面,还有其他,具体的大家可以看看官方手册。

文章来源:智云一二三科技

文章标题:「服务器」协程探秘,你知多少

文章地址:https://www.zhihuclub.com/77096.shtml

关于作者: 智云科技

热门文章

网站地图