php协程处理报表,php基于协程实现异步的方法分析

本文实例讲述了php基于协程实现异步的方法。分享给大家供大家参考,具体如下:

github上php的协程大部分是根据这篇文章实现的:http://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html。

它们最终的结果都是把回调变成了优雅的顺序执行的代码,但还是阻塞的,不是真正的异步。

比如最热门的:https://github.com/recoilphp/recoil

先安装:

composer require recoil/recoil

执行:

//recoil.php

include __DIR__ . '/vendor/autoload.php';

use Recoil\React\ReactKernel;

$i = 100000;

ReactKernel::start(task1());

ReactKernel::start(task2());

function task1(){

global $i;

echo "wait start" . PHP_EOL;

while ($i-- > 0) {

yield;

}

echo "wait end" . PHP_EOL;

};

function task2(){

echo "Hello " . PHP_EOL;

yield;

echo "world!" . PHP_EOL;

}

结果:

wait start

//等待若干秒

wait end

Hello

world!

我本来是想让两个任务并行,结果两个任务变成了串行,中间等待的时间什么事情都干不了。React响应式的编程是严格禁止这种等待的,所以我就参照unity3d的协程自己写了个php版本的。上代码:

//Coroutine.php

//依赖swoole实现的定时器,也可以用其它方法实现定时器

class Coroutine

{

//可以根据需要更改定时器间隔,单位ms

const TICK_INTERVAL = 1;

private $routineList;

private $tickId = -1;

public function __construct()

{

$this->routineList = [];

}

public function start(Generator $routine)

{

$task = new Task($routine);

$this->routineList[] = $task;

$this->startTick();

}

public function stop(Generator $routine)

{

foreach ($this->routineList as $k => $task) {

if($task->getRoutine() == $routine){

unset($this->routineList[$k]);

}

}

}

private function startTick()

{

swoole_timer_tick(self::TICK_INTERVAL, function($timerId){

$this->tickId = $timerId;

$this->run();

});

}

private function stopTick()

{

if($this->tickId >= 0) {

swoole_timer_clear($this->tickId);

}

}

private function run()

{

if(empty($this->routineList)){

$this->stopTick();

return;

}

foreach ($this->routineList as $k => $task) {

$task->run();

if($task->isFinished()){

unset($this->routineList[$k]);

}

}

}

}

class Task

{

protected $stack;

protected $routine;

public function __construct(Generator $routine)

{

$this->routine = $routine;

$this->stack = new SplStack();

}

/**

* [run 协程调度]

* @return [type] [description]

*/

public function run()

{

$routine = &$this->routine;

try {

if(!$routine){

return;

}

$value = $routine->current();

//嵌套的协程

if ($value instanceof Generator) {

$this->stack->push($routine);

$routine = $value;

return;

}

//嵌套的协程返回

if(!$routine->valid() && !$this->stack->isEmpty()) {

$routine = $this->stack->pop();

}

$routine->next();

} catch (Exception $e) {

if ($this->stack->isEmpty()) {

/*

throw the exception

*/

return;

}

}

}

/**

* [isFinished 判断该task是否完成]

* @return boolean [description]

*/

public function isFinished()

{

return $this->stack->isEmpty() && !$this->routine->valid();

}

public function getRoutine()

{

return $this->routine;

}

}

测试代码:

//test.php

require 'Coroutine.php';

$i = 10000;

$c = new Coroutine();

$c->start(task1());

$c->start(task2());

function task1(){

global $i;

echo "wait start" . PHP_EOL;

while ($i-- > 0) {

yield;

}

echo "wait end" . PHP_EOL;

};

function task2(){

echo "Hello " . PHP_EOL;

yield;

echo "world!" . PHP_EOL;

}

结果:

wait start

Hello

world!

//等待几秒,但不阻塞

wait end

希望本文所述对大家PHP程序设计有所帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值