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 身份验证方面的函数
Oct 11 PHP
PHP代码保护--Zend Guard的使用详解
Jun 03 PHP
php使用mb_check_encoding检查字符串在指定的编码里是否有效
Nov 07 PHP
php获取目标函数执行时间示例
Mar 04 PHP
php字符串按照单词进行反转的方法
Mar 14 PHP
CodeIgniter配置之autoload.php自动加载用法分析
Jan 20 PHP
PHP闭包函数详解
Feb 13 PHP
详谈PHP中的密码安全性Password Hashing
Feb 04 PHP
PHP实现表单提交数据的验证处理功能【防SQL注入和XSS攻击等】
Jul 21 PHP
浅谈PHP发送HTTP请求的几种方式
Jul 25 PHP
PHP时间处理类操作示例
Sep 05 PHP
利用PHP扩展Xhprof分析项目性能实践教程
Sep 05 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
虹吸式咖啡探讨–研磨
2021/03/03 冲泡冲煮
PHP学习之字符串比较和查找
2011/04/17 PHP
今天你说520了吗?不仅有php表白书还有java表白神器
2016/05/20 PHP
动态添加js事件实现代码
2009/03/12 Javascript
关于COOKIE个数与大小的问题
2011/01/17 Javascript
JavaScript 放大镜 放大倍率和视窗尺寸
2011/05/09 Javascript
js函数调用常用方法详解
2012/12/03 Javascript
jQuery关于导航条背景切换效果实现示例
2013/09/04 Javascript
可选择和输入的下拉列表框示例
2013/11/05 Javascript
JavaScript实现按Ctrl键打开新页面
2014/09/04 Javascript
学习javascript面向对象 实例讲解面向对象选项卡
2016/01/04 Javascript
javascript 中null和undefined区分和比较
2017/04/19 Javascript
JS实现百度搜索接口及链接功能实例代码
2018/02/02 Javascript
JavaScript 截取字符串代码实例
2019/09/05 Javascript
搭建Vue从Vue-cli到router路由护卫的实现
2019/11/14 Javascript
微信小程序仿抖音短视频切换效果的实例代码
2020/06/24 Javascript
Vue封装全局过滤器Filters的步骤
2020/09/16 Javascript
vue+openlayers绘制省市边界线
2020/12/24 Vue.js
[01:07:41]IG vs VGJ.T 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
python 读写、创建 文件的方法(必看)
2016/09/12 Python
centos 安装python3.6环境并配置虚拟环境的详细教程
2018/02/22 Python
使用python telnetlib批量备份交换机配置的方法
2019/07/25 Python
python2和python3应该学哪个(python3.6与python3.7的选择)
2019/10/01 Python
Python sorted排序方法如何实现
2020/03/31 Python
Python pip使用超时问题解决方案
2020/08/03 Python
python 实现表情识别
2020/11/21 Python
工商管理专业职业生涯规划
2014/01/01 职场文书
合唱兴趣小组活动总结
2014/07/10 职场文书
企业挂职心得体会
2014/09/10 职场文书
党员对照检查材料
2014/09/22 职场文书
幼儿园老师个人总结
2015/02/28 职场文书
售房协议书范本
2015/08/11 职场文书
英语导游欢迎词
2015/09/30 职场文书
幼儿园大班教师评语
2019/06/21 职场文书
如何判断pytorch是否支持GPU加速
2021/06/01 Python
redis不能访问本机真实ip地址的解决方案
2021/07/07 Redis