当前位置:首页 > PHP教程 > php高级应用 > 列表

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

发布:smiling 来源: PHP粉丝网  添加日期:2021-12-04 20:35:19 浏览: 评论:0 

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

执行:

  1. <?php 
  2. //recoil.php 
  3. include __DIR__ . '/vendor/autoload.php'
  4. use Recoil\React\ReactKernel; 
  5. $i = 100000; 
  6. ReactKernel::start(task1()); 
  7. ReactKernel::start(task2()); 
  8. function task1(){ 
  9.   global $i
  10.   echo "wait start" . PHP_EOL; 
  11.   while ($i-- > 0) { 
  12.     yield; 
  13.   } 
  14.   echo "wait end" . PHP_EOL; 
  15. }; 
  16. function task2(){ 
  17.   echo "Hello " . PHP_EOL; 
  18.   yield; 
  19.   echo "world!" . PHP_EOL; 

结果:

  1. wait start 
  2. //等待若干秒 
  3. wait end 
  4. Hello 
  5. world! 

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

  1. <?php 
  2. //Coroutine.php 
  3. //依赖swoole实现的定时器,也可以用其它方法实现定时器 
  4. class Coroutine 
  5.   //可以根据需要更改定时器间隔,单位ms 
  6.   const TICK_INTERVAL = 1; 
  7.   private $routineList
  8.   private $tickId = -1; 
  9.   public function __construct() 
  10.   { 
  11.     $this->routineList = []; 
  12.   } 
  13.   public function start(Generator $routine
  14.   { 
  15.     $task = new Task($routine); 
  16.     $this->routineList[] = $task
  17.     $this->startTick(); 
  18.   } 
  19.   public function stop(Generator $routine
  20.   { 
  21.     foreach ($this->routineList as $k => $task) { 
  22.       if($task->getRoutine() == $routine){ 
  23.         unset($this->routineList[$k]); 
  24.       } 
  25.     } 
  26.   } 
  27.   private function startTick() 
  28.   { 
  29.     swoole_timer_tick(self::TICK_INTERVAL, function($timerId){ 
  30.       $this->tickId = $timerId
  31.       $this->run(); 
  32.     }); 
  33.   } 
  34.   private function stopTick() 
  35.   { 
  36.     if($this->tickId >= 0) { 
  37.       swoole_timer_clear($this->tickId); 
  38.     } 
  39.   } 
  40.   private function run() 
  41.   { 
  42.     if(emptyempty($this->routineList)){ 
  43.       $this->stopTick(); 
  44.       return
  45.     } 
  46.     foreach ($this->routineList as $k => $task) { 
  47.       $task->run(); 
  48.       if($task->isFinished()){ 
  49.         unset($this->routineList[$k]); 
  50.       } 
  51.     } 
  52.   } 
  53.     
  54. class Task 
  55.   protected $stack
  56.   protected $routine
  57.   public function __construct(Generator $routine
  58.   { 
  59.     $this->routine = $routine
  60.     $this->stack = new SplStack(); 
  61.   } 
  62.   /** 
  63.    * [run 协程调度] 
  64.    * @return [type]     [description] 
  65.    */ 
  66.   public function run() 
  67.   { 
  68.     $routine = &$this->routine; 
  69.     try { 
  70.       if(!$routine){ 
  71.         return
  72.       } 
  73.       $value = $routine->current(); 
  74.       //嵌套的协程 
  75.       if ($value instanceof Generator) { 
  76.         $this->stack->push($routine); 
  77.         $routine = $value
  78.         return
  79.       } 
  80.       //嵌套的协程返回 
  81.       if(!$routine->valid() && !$this->stack->isEmpty()) { 
  82.         $routine = $this->stack->pop(); 
  83.       } 
  84.       $routine->next(); 
  85.     } catch (Exception $e) { 
  86.       if ($this->stack->isEmpty()) { 
  87.         /* 
  88.           throw the exception 
  89.         */ 
  90.         return
  91.       } 
  92.     } 
  93.   } 
  94.   /** 
  95.    * [isFinished 判断该task是否完成] 
  96.    * @return boolean [description] 
  97.    */ 
  98.   public function isFinished() 
  99.   { 
  100.     return $this->stack->isEmpty() && !$this->routine->valid(); 
  101.   } 
  102.   public function getRoutine() 
  103.   { 
  104.     return $this->routine; 
  105.   } 

测试代码:

  1. <?php 
  2. //test.php 
  3.  require 'Coroutine.php'
  4. $i = 10000; 
  5. $c = new Coroutine(); 
  6. $c->start(task1()); 
  7. $c->start(task2()); 
  8. function task1(){ 
  9.   global $i
  10.   echo "wait start" . PHP_EOL; 
  11.   while ($i-- > 0) { 
  12.     yield; 
  13.   } 
  14.   echo "wait end" . PHP_EOL; 
  15. }; 
  16. function task2(){ 
  17.   echo "Hello " . PHP_EOL; 
  18.   yield; 
  19.   echo "world!" . PHP_EOL; 

结果:

  1. wait start 
  2. Hello 
  3. world! 
  4. //等待几秒,但不阻塞 
  5. wait end

Tags: php协程 php异步

分享到: