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


Posted in PHP onJuly 17, 2019

本文实例讲述了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编程语言开发动态WAP页面
Oct 09 PHP
简单PHP上传图片、删除图片实现代码
May 12 PHP
PHP中文件上传的一个问题
Sep 04 PHP
php多层数组与对象的转换实例代码
Aug 05 PHP
php获取mysql字段名称和其它信息的例子
Apr 14 PHP
PHP中余数、取余的妙用
Jun 29 PHP
使用Composer安装Yii框架的方法
Mar 15 PHP
PHP-FPM和Nginx的通信机制详解
Feb 01 PHP
php设计模式之装饰模式应用案例详解
Jun 17 PHP
PHP常用函数之格式化时间操作示例
Oct 21 PHP
PHP反射基础知识回顾
Sep 10 PHP
php中yii框架实例用法
Dec 22 PHP
php学习笔记之字符串常见操作总结
Jul 16 #PHP
thinkPHP+mysql+ajax实现的仿百度一下即时搜索效果详解
Jul 15 #PHP
[原创]PHP global全局变量经典应用与注意事项分析【附$GLOBALS用法对比】
Jul 12 #PHP
php array_chunk()函数用法与注意事项
Jul 12 #PHP
laravel框架中间件 except 和 only 的用法示例
Jul 12 #PHP
Laravel框架实现多数据库连接操作详解
Jul 12 #PHP
php遍历目录下文件并按修改时间排序操作示例
Jul 12 #PHP
You might like
解析php如何将日志写进syslog
2013/06/28 PHP
php实现图片添加描边字和马赛克的方法
2014/12/10 PHP
yii使用activeFileField控件实现上传文件与图片的方法
2015/12/28 PHP
100多行PHP代码实现socks5代理服务器[2]
2016/05/05 PHP
PHP实现下载远程图片保存到本地的方法
2017/06/19 PHP
php 可变函数使用小结
2018/06/12 PHP
js获取html参数及向swf传递参数应用介绍
2013/02/18 Javascript
jQuery之尺寸调整组件的深入解析
2013/06/19 Javascript
Node.js模拟浏览器文件上传示例
2014/03/26 Javascript
jQuery实现的仿百度分页足迹效果代码
2015/10/30 Javascript
谈一谈js中的执行环境及作用域
2016/03/30 Javascript
jQuery 跨域访问解决原理案例详解
2016/07/09 Javascript
jQuery Easyui Tabs扩展根据自定义属性打开页签
2016/08/15 Javascript
js点击按钮实现水波纹效果代码(CSS3和Canves)
2016/09/15 Javascript
JS跨域请求外部服务器的资源
2017/02/06 Javascript
jquery横向纵向鼠标滚轮全屏切换
2017/02/27 Javascript
jquery中$.fn和图片滚动效果实现的必备知识总结
2017/04/21 jQuery
ES6使用Set数据结构实现数组的交集、并集、差集功能示例
2017/10/31 Javascript
JS遍历DOM文档树的方法实例详解
2018/04/03 Javascript
Webpack5正式发布,有哪些新特性
2020/10/12 Javascript
python实现简单ftp客户端的方法
2015/06/28 Python
使用Python编写爬虫的基本模块及框架使用指南
2016/01/20 Python
人机交互程序 python实现人机对话
2017/11/14 Python
Python类的继承、多态及获取对象信息操作详解
2019/02/28 Python
Python 实现交换矩阵的行示例
2019/06/26 Python
Python图像处理库PIL的ImageDraw模块介绍详解
2020/02/26 Python
在Python中字典按值排序的实现方法
2020/11/12 Python
购买大码女装:Lane Bryant
2016/09/07 全球购物
美国眼镜网站:LensCrafters
2020/01/19 全球购物
空指针到底是什么
2012/08/07 面试题
自考自我鉴定范文
2013/10/30 职场文书
同学聚会老师邀请函
2014/01/28 职场文书
《在山的那边》教学反思
2014/02/23 职场文书
2015中秋节晚会开场白
2015/07/30 职场文书
护士爱岗敬业心得体会
2016/01/25 职场文书
Python 文字识别
2022/05/11 Python