php基于协程实现异步的方法分析
作者:llj1985 时间:2023-06-11 10:08:39
本文实例讲述了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程序设计有所帮助。
来源:https://blog.csdn.net/llj1985/article/details/51684210
标签:php,协程,异步
0
投稿
猜你喜欢
解析Mybatis对sql表的一对多查询问题
2024-01-14 11:33:19
Python 数据结构之旋转链表
2021-05-04 15:39:28
eBay 打造基于 Apache Druid 的大数据实时监控系统
2022-12-25 21:54:37
kafka监控获取指定topic的消息总量示例
2023-09-04 01:44:48
4个Web图片在线压缩优化工具
2009-10-13 21:02:00
JavaScript"模拟事件"的注意要点详解
2024-04-30 09:56:47
python ChainMap的使用详解
2023-10-31 18:02:40
使用Golang的Context管理上下文的方法
2023-06-29 06:37:23
pycharm进入时每次都是insert模式的解决方式
2023-08-09 09:52:16
SQL中位数函数实例
2024-01-25 17:21:55
js中各浏览器中鼠标按键值的差异
2024-05-05 09:15:28
Python+NumPy绘制常见曲线的方法详解
2022-01-11 06:14:43
在函数间不能传递32个以上参数的疑难问题
2008-12-31 13:31:00
vue2.0 解决抽取公用js的问题
2024-05-28 15:59:28
Python tkinter事件高级用法实例
2023-12-09 10:28:17
MySQL数据库事务与锁深入分析
2024-01-28 19:03:12
MySQL 字符串截取相关函数小结
2024-01-14 21:37:14
python截取两个单词之间的内容方法
2022-06-02 01:48:46
Python使用random模块生成随机数操作实例详解
2022-06-28 21:50:27
python制作小说爬虫实录
2023-09-30 17:39:25