加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 钦州站长网 (https://www.0777zz.com/)- 智能办公、应用安全、终端安全、数据可视化、人体识别!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

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

发布时间:2023-10-24 10:31:46 所属栏目:PHP教程 来源:转载
导读:   本文实例讲述了php基于协程实现异步的方法。分享给大家供大家参考,具体如下:



  github上php的协程大部分是根据这篇文章实现的:http://nikic.github.io/2012/12/22/Cooperat
  本文实例讲述了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编程网 - 钦州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章