首页 > 语言 > PHP > 正文

php基于协程实现异步的方法分析

2024-05-05 00:10:22
字体:
来源:转载
供稿:网友

本文实例讲述了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

执行:

<?php//recoil.phpinclude __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版本的。上代码:

<?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;  }}

测试代码:

<?php//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程序设计有所帮助。


注:相关教程知识阅读请移步到PHP教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选