所以Task的构造函数中就是接收一个闭包函数,我们命名为coroutine。
/**
* Task任务类
*/
class Task
{
protected $taskId;
protected $coroutine;
protected $beforeFirstYield = true;
protected $sendValue;
/**
* Task constructor.
* @param $taskId
* @param Generator $coroutine
*/
public function __construct($taskId, Generator $coroutine)
{
$this->taskId = $taskId;
$this->coroutine = $coroutine;
}
/**
* 获取当前的Task的ID
*
* @return mixed
*/
public function getTaskId()
{
return $this->taskId;
}
/**
* 判断Task执行完毕了没有
*
* @return bool
*/
public function isFinished()
{
return !$this->coroutine->valid();
}
/**
* 设置下次要传给协程的值,比如 $id = (yield $xxxx),这个值就给了$id了
*
* @param $value
*/
public function setSendValue($value)
{
$this->sendValue = $value;
}
/**
* 运行任务
*
* @return mixed
*/
public function run()
{
// 这里要注意,生成器的开始会reset,所以第一个值要用current获取
if ($this->beforeFirstYield) {
$this->beforeFirstYield = false;
return $this->coroutine->current();
} else {
// 我们说过了,用send去调用一个生成器
$retval = $this->coroutine->send($this->sendValue);
$this->sendValue = null;
return $retval;
}
}
}
2)Scheduler实现
接下来就是Scheduler这个重点核心部分,他扮演着调度员的角色。
/**
* Class Scheduler
*/
Class Scheduler
{
/**
* @var SplQueue
*/
protected $taskQueue;
/**
* @var int
*/
protected $tid = 0;
/**
* Scheduler constructor.
*/
public function __construct()
{
/* 原理就是维护了一个队列,
* 前面说过,从编程角度上看,协程的思想本质上就是控制流的主动让出(yield)和恢复(resume)机制
* */
$this->taskQueue = new SplQueue();
}
/**
* 增加一个任务
*
* @param Generator $task
* @return int
*/
public function addTask(Generator $task)
{
$tid = $this->tid;
$task = new Task($tid, $task);
$this->taskQueue->enqueue($task);
$this->tid++;
return $tid;
}
/**
* 把任务进入队列
*
* @param Task $task
*/
public function schedule(Task $task)
{
$this->taskQueue->enqueue($task);
}
/**
* 运行调度器
*/
public function run()
{
while (!$this->taskQueue->isEmpty()) {
// 任务出队
$task = $this->taskQueue->dequeue();
$res = $task->run(); // 运行任务直到 yield
if (!$task->isFinished()) {
$this->schedule($task); // 任务如果还没完全执行完毕,入队等下次执行
}
}
}
}
这样我们基本就实现了一个协程调度器。
你可以使用下面的代码来测试:
<?php
function task1() {
for ($i = 1; $i <= 10; ++$i) {
echo "This is task 1 iteration $i.\n";
yield; // 主动让出CPU的执行权
}
}
function task2() {
for ($i = 1; $i <= 5; ++$i) {
echo "This is task 2 iteration $i.\n";
yield; // 主动让出CPU的执行权
}
}
$scheduler = new Scheduler; // 实例化一个调度器
$scheduler->newTask(task1()); // 添加不同的闭包函数作为任务
$scheduler->newTask(task2());
$scheduler->run();
关键说下在哪里能用得到PHP协程。
function task1() {
/* 这里有一个远程任务,需要耗时10s,可能是一个远程机器抓取分析远程网址的任务,我们只要提交最后去远程机器拿结果就行了 */
remote_task_commit();
// 这时候请求发出后,我们不要在这里等,主动让出CPU的执行权给task2运行,他不依赖这个结果
yield;
yield (remote_task_receive());
...
}
function task2() {
for ($i = 1; $i <= 5; ++$i) {
echo "This is task 2 iteration $i.\n";
yield; // 主动让出CPU的执行权
}
}
这样就提高了程序的执行效率。
关于『系统调用』的实现,鸟哥已经讲得很明白,我这里不再说明。
3)协程堆栈
鸟哥文中还有一个协程堆栈的例子。
我们上面说过了,如果在函数中使用了yield,就不能当做函数使用。
PHP有序表查找之插值查找算法示例这篇文章主要介绍了PHP有序表查找之插值查找算法,简单分析了插值查找算法的概念、原理并结合实例形式分析了php实
ThinkPHP整合datatables实现服务端分页的示例代码下面小编就为大家分享一篇ThinkPHP整合datatables实现服务端分页的示例代码,具有很好的参考价值,希望对大家有所帮
PHP实现APP微信支付的实例讲解下面小编就为大家分享一篇PHP实现APP微信支付的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小
PHP实现的多维数组排序算法分析这篇文章主要介绍了PHP实现的多维数组排序算法,结合实例形式对比分析了php针对多维数组及带有键名的多维数组进行
php+ajax实现无刷新文件上传功能(ajaxuploadfile)这篇文章主要为大家详细介绍了php结合ajaxuploadfile实现无刷新文件上传功能,具有一定的参考价值,感兴趣的小伙伴们
PHP的RSA加密解密方法以及开发接口使用本篇文章给大家详细介绍了PHP开发接口使用RSA进行加密解密方法,对此有兴趣的朋友可以学习下。