php基于协程实现异步的方法分析
时间:2022-07-27
本文章向大家介绍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 RecoilReactReactKernel;
$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
- javascript读写本机文本文件
- 崔立鹏:腾讯云为知识竞技游戏提供解决方案
- Mysql之binlog日志说明及利用binlog日志恢复数据操作记录
- 常用的AJAX弹出层代码
- Linux下检测IP地址冲突及解决方法
- linux如何挂载windows下的共享文件
- silverlight2中的定时器,以及如何动态改变控件的坐标
- 定时备份windows机器上的文件到linux服务器上的操作梳理(rsync)
- jQuery1.3以上版本"@"的问题
- 龚宏绩:三七互娱游戏上云的现状与未来
- Android 程序打包及签名
- 韩伟:解谜腾讯游戏海量服务架构
- Message和handler传递对象
- MVC RC2中关于HtmlHelper给DropDownList设置初始选中值的问题
- php概述
- php教程
- php环境搭建
- PHP书写格式
- php变量
- php常量
- PHP注释
- php数组
- php字符串 string
- PHP整型 integer
- PHP浮点型 float
- php布尔型
- php数据类型之数组
- php数据类型之对象
- php数据类型之null
- php数据类型之间的转换
- php运算符
- php表达式
- PHP循环控制
- PHP流程控制
- php函数
- php全局变量
- PHP魔术变量
- php命名空间
- php 日期
- PHP包含文件
- php文件
- PHP 文件上传
- php Cookies
- php Sessions
- php email
- php安全email
- php错误处理
- PHP异常处理
- php过滤器
- PHP 高级过滤器
- php json
- php 表单
- PHP MySQL 简介
- PHP 连接 MySQL
- php创建数据库
- php 创建表
- php mysq 插入数据
- PHP MySQL 插入多条数据
- PHP MySQL 预处理语句
- php mysql 读取数据
- php mysql where
- PHP MySQL Order By
- PHP MySQL Update
- PHP MySQL Delete
- php ODBC
- 浙大版《C语言程序设计(第3版)》题目集 习题10-1 判断满足条件的三位数
- 差分标记-HDU1556 Color the ball
- flink cep 案例之机架温度监控报警
- 详解flink 1.11中的新部署模式-Application模式
- 浙大版《C语言程序设计(第3版)》题目集 习题10-2 递归求阶乘和
- hadoop源码解析之RPC分析
- 存储过程和触发器
- hadoop源码学习之namenode启动
- 浙大版《C语言程序设计(第3版)》题目集 习题10-3 递归实现指数函数
- hadoop2.7.3源码解析之datanode注册和心跳机制
- 审核/审计
- flink教程-聊聊 flink 1.11 中新的水印策略
- 浙大版《C语言程序设计(第3版)》题目集 习题10-4 递归求简单交错幂级数的部分和
- JSP分页显示(前端处理)
- 拓扑排序-HDU2647 Reward