• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    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
    
    

    执行:

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

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

    您可能感兴趣的文章:
    • 详解php协程知识点
    • PHP生成器(generator)和协程的实现方法详解
    • PHP7下协程的实现方法详解
    • 关于PHP中协程和阻塞的一些理解与思考
    • PHP 进程池与轮询调度算法实现多任务的示例代码
    • PHP定时执行计划任务的多种方法小结
    • php定时计划任务的实现方法详解
    • php守护进程 加linux命令nohup实现任务每秒执行一次
    • PHP中使用sleep函数实现定时任务实例分享
    • PHP实现简单的协程任务调度demo示例
    上一篇:php学习笔记之字符串常见操作总结
    下一篇:php和C#的yield迭代器实现方法对比分析
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯

    时间:9:00-21:00 (节假日不休)

    地址:江苏信息产业基地11号楼四层

    《增值电信业务经营许可证》 苏B2-20120278

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