首页 » php » php 用yield实现异步web server

php 用yield实现异步web server

 
文章目录

php在php5.5的时候引入了generator和coroutine,从核心上提出了一种方法去写不阻塞的IO,当然这和node的event loop还是有比较大的区别的,它的主要理念是: 把几个大任务分别分成多个小步轮流执行,有某个小任务在等待系统io的话,就跳过它,执行下一个小任务,这样总体提升了代码的效率 。

0x1:yield表达式是什么?

非常简单,描述yield表达式的只有两个关键词: 中断点占位符 (自己总结的两点,只属于一种感性的记忆方式,并不是官方给出的专业词汇)。

举个简单的例子:

function gen() {
	$tid = (yield 1 + 1); 
	for ($i = 1; $i <= 10; ++$i) {
		echo "This is $tid task iteration $i.\n";
		yield $i;
	}
}
//$t1是[generator](http://php.net/manual/en/class.generator.php)类的实例(instance)
$t1 = gen();
//取出yield后面的表达式的结构,并没有进行赋值就暂停了当前的操作 </span><span class="hljs-string">$tid</span><span class="hljs-string"> = (</span><span class="hljs-string">yield</span> <span class="hljs-string">1</span><span class="hljs-string"> + </span><span class="hljs-string">1</span><span class="hljs-string">) ,(特性一:中断点)
$r1 = $t1->current(); 
//结果为 2 
echo $r1; 
//将字符'+++'(特性二:占位符),替换到刚才暂停的地方 </span><span class="hljs-string">$tid</span><span class="hljs-string"> = </span><span class="hljs-string">'+++++'</span><span class="hljs-string">,并进入for循环,遇见yield表达式,获取yield 表达式后面的值,并保存当前的局部变量的值,yield后面是$i,返回$i
var_dump($t1->send('+++')); 

这里 current 方法是暂停并返回获取当前 yield 表达式的值。 send 方法是先替换之前暂停时的 yield表达式 所处的位置的值,再开始执行,直到遇到下一个 yield表达式 ,再取表达式的结果,暂停并保存当前的局部变量的值。 在这里我注意到send方法总是同时得确定两个yield表达式的位置,第一个yield表达式的值被替换,再去寻找第二个表达式的值(yield $i里面的$i),再次保存当前的状态,返回 yield表达式 后面的值。依次类推 。 这里有个需要思考的问题就是如果一开始就用send方法不用current()会怎么样? 答案是send方法在第一次运行之前会隐含调用rewind方法,会在函数第一个yield的地方中断保存局部变量,但是忽略它的返回值。

0x2: coroutine是什么?

Coroutines are computer program components that generalize subroutines for nonpreemptive multitasking, by allowing multiple entry points for suspending and resuming execution at certain locations.

简单的说:coroutine(协同程序) 提供一种方法中断当前执行,保存当前的局部变量,下次再过来又可以恢复当前局部变量继续执行。在php里就是几个大的任务分别分成小的任务,轮流执行。而中断和恢复就是靠的 yield 表达式来实现。

0x3: 使用 yield表达式 实现非阻塞IO的例子

在这里主要有三个参与对象共同去实现任务调度: Task , Scheduler , SystemCall .

  1. Task 对象以Generator对象为参数初始化,一个 Task 分成了多个小步执行。
  2. Scheduler 对象负责调度任务,什么叫做调度呢?就是分别轮流执行多个 Task 对象的每一步,如果某一步还在等待IO就跳过去这一步。
  3. SystemCallTask 的一个小步,假设Task A 对象的多个小步为 ‘——+——‘, 执行到 + 这一步就执行SystemCall的任务。

    还有一些额外的对象去给任务调度添加功能:

  4. CoroutineReturnValue 把数值类型封装成类,用在处理coroutine之间的嵌套。
  5. CoSocket 封装了socket的系列操作。
  6. Log 输出日志到cli。

    具体怎么实现,还是源码来的实在,仓库地址 https://github.com/Jamlee/coroutine

参考文档:

http://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html

原文链接:php 用yield实现异步web server,转载请注明来源!

0