侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

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

2022-07-14 星期四 / 0 评论 / 0 点赞 / 44 阅读 / 5107 字

本文实例讲述了php基于协程实现异步的方法。分享给大家供大家参考,具体如下:github上php的协程大部分是根据这篇文章实现的:http://nikic.github.io/2012/12/22/Cooperative

本文实例讲述了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扩展开发教程》、《PHP网络编程技巧总结》、《php curl用法总结》、《PHP数组(Array)操作技巧大全》、《PHP数据结构与算法教程》、《php程序设计算法总结》及《php字符串(string)用法总结

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

广告 广告

评论区