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后面的表达式的结构,并没有进行赋值就暂停了当前的操作 `$tid = (yield 1 + 1) `,(特性一:中断点)
$r1 = $t1->current(); 
//结果为 2 
echo $r1; 
//将字符'+++'(特性二:占位符),替换到刚才暂停的地方 `$tid = '+++++'`,并进入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/Cooperat...

file

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!