ReactPHP 异步操作封装

ReactPHP 异步操作封装

功能概述

封装一个异步操作方法,确保传入的函数不会阻塞后续代码执行。

依赖安装

1
composer require react/event-loop react/promise

实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php

use React\EventLoop\Loop;
use React\Promise\Deferred;

/**
* 异步执行回调函数,不阻塞事件循环
* @param callable $callback 需要异步执行的回调函数
* @return \React\Promise\Promise 返回 Promise 对象用于处理结果
*/
function asyncOperation(callable $callback): \React\Promise\Promise
{
$deferred = new Deferred();

// 获取当前事件循环实例
$loop = Loop::get();

// 在下一个事件循环 tick 中执行回调
$loop->futureTick(function () use ($callback, $deferred) {
try {
// 执行回调并获取结果
$result = $callback();
$deferred->resolve($result);
} catch (\Throwable $e) {
// 捕获异常并拒绝 promise
$deferred->reject($e);
}
});

return $deferred->promise();
}

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

require __DIR__ . '/vendor/autoload.php';

// 正确使用示例(非阻塞)
asyncOperation(function () {
// 模拟异步操作(不能使用同步阻塞代码)
return '异步操作完成';
})->then(function ($result) {
echo $result; // 输出:异步操作完成
})->otherwise(function (\Throwable $e) {
echo '出错:' . $e->getMessage();
});

// 后续代码会立即执行
echo "立即执行的内容\n";

// 错误使用示例(同步阻塞代码仍然会阻塞)
asyncOperation(function () {
sleep(2); // 同步阻塞操作
return '这仍然会阻塞2秒';
})->then(function ($result) {
echo $result;
});

注意事项

  1. 不要使用同步阻塞代码

    • 避免 sleep()file_get_contents() 等同步阻塞操作
    • 使用 ReactPHP 提供的异步替代方案
  2. 推荐异步操作方式

    1
    2
    3
    4
    // 正确:使用 ReactPHP 的异步 HTTP 客户端
    asyncOperation(function () use ($client) {
    return $client->request('GET', 'https://api.example.com');
    });
  3. CPU 密集型任务

    • 建议使用多进程方案处理
    • 可考虑 workerman 等扩展

常见问题

Q: 为什么我的异步操作仍然阻塞?
A: 检查回调函数中是否包含同步阻塞代码,如 sleep()file_get_contents()

Q: 如何处理 CPU 密集型任务?
A: 使用多进程方案,ReactPHP 不适合处理 CPU 密集型任务

完整示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php

require __DIR__ . '/vendor/autoload.php';

// 异步执行多个任务
$promises = [
asyncOperation(function () {
return "任务1完成";
}),
asyncOperation(function () {
return "任务2完成";
}),
asyncOperation(function () {
return "任务3完成";
})
];

// 等待所有任务完成
React\Promise\all($promises)->then(function ($results) {
print_r($results);
})->otherwise(function (\Throwable $e) {
echo '出错:' . $e->getMessage();
});

// 保持事件循环运行(实际应用中通常由 HTTP 服务器等保持)
Loop::get()->addTimer(1, function () {
Loop::get()->stop();
});

这个封装提供了简单易用的异步操作方式,适用于大多数 ReactPHP 异步编程场景。