使用 ReactPHP 和 Workerman 实现多线程和异步操作
在 PHP 中,虽然本身并不支持真正的多线程(像 Java 或 C++ 那样),但我们可以通过异步编程来实现类似的并发效果。下面分别介绍如何使用 ReactPHP 和 Workerman 实现多线程和异步操作的功能。
1. 使用 ReactPHP 实现异步操作
ReactPHP 是一个事件驱动的 PHP 库,它允许你以异步和非阻塞的方式编写代码。通过使用它,你可以实现类似“多线程”的异步操作。
示例:异步 HTTP 请求
<?php
require 'vendor/autoload.php';
use React\EventLoop\Factory;
use React\Http\Browser;
$loop = Factory::create();
$client = new Browser($loop);
// 模拟多个异步 HTTP 请求
$urls = [
'https://jsonplaceholder.typicode.com/posts/1',
'https://jsonplaceholder.typicode.com/posts/2',
'https://jsonplaceholder.typicode.com/posts/3',
];
$promises = [];
foreach ($urls as $url) {
$promises[] = $client->get($url)->then(
function (Psr\Http\Message\ResponseInterface $response) {
echo "Response received: " . $response->getBody() . PHP_EOL;
},
function (Exception $e) {
echo "Error: " . $e->getMessage() . PHP_EOL;
}
);
}
// 等待所有请求完成
\React\Promise\all($promises)->then(function () {
echo "All requests completed!" . PHP_EOL;
});
$loop->run();
解释:
React\EventLoop\Factory::create()
创建了事件循环。React\Http\Browser
是一个支持异步 HTTP 请求的客户端。React\Promise\all()
等待所有异步任务完成。
通过这种方式,多个 HTTP 请求会并行执行,而不会阻塞主线程。
示例:异步文件 I/O
<?php
require 'vendor/autoload.php';
use React\EventLoop\Factory;
use React\Stream\ReadableResourceStream;
$loop = Factory::create();
// 打开一个异步文件流
$filePath = 'example.txt';
$stream = new ReadableResourceStream(fopen($filePath, 'r'), $loop);
$stream->on('data', function ($chunk) {
echo "Read chunk: " . $chunk . PHP_EOL;
});
$stream->on('end', function () {
echo "File reading completed!" . PHP_EOL;
});
$loop->run();
解释:
ReadableResourceStream
用于异步读取文件内容。- 事件绑定(如
on('data')
和on('end')
)定义了读取文件时的操作。
2. 使用 Workerman 实现多线程和异步操作
Workerman 是一个高性能的 PHP 多进程框架,非常适合实现异步 I/O 和并行任务处理。
示例:多线程(多进程)任务处理
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
// 创建一个 Worker 进程,监听 2345 端口
$worker = new Worker('http://0.0.0.0:2345');
// 启动 4 个进程(模拟多线程)
$worker->count = 4;
// 每个进程处理客户端请求
$worker->onMessage = function ($connection, $data) {
$connection->send('Hello from worker PID: ' . posix_getpid());
};
// 启动 Worker
Worker::runAll();
解释:
Worker
是 Workerman 的核心类,用于创建和管理多进程。Worker::count
设置了进程数(例如 4 表示 4 个进程)。- 每个进程独立运行并处理客户端请求。
访问 http://localhost:2345
时,会随机由 4 个进程中的一个响应请求。
示例:异步操作(定时任务)
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
// 创建一个 Worker 进程
$worker = new Worker();
// 设置定时任务
$worker->onWorkerStart = function () {
// 每秒执行一次
\Workerman\Lib\Timer::add(1, function () {
echo "Task executed at " . date('Y-m-d H:i:s') . PHP_EOL;
});
};
// 启动 Worker
Worker::runAll();
解释:
Timer::add()
用于添加定时任务。- 任务会按照指定的时间(1 秒)间隔执行。
示例:异步 HTTP 请求
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
use Workerman\Lib\Timer;
use GuzzleHttp\Client;
// 创建一个 Worker 进程
$worker = new Worker();
$worker->onWorkerStart = function () {
$client = new Client();
// 模拟多个异步 HTTP 请求
$urls = [
'https://jsonplaceholder.typicode.com/posts/1',
'https://jsonplaceholder.typicode.com/posts/2',
'https://jsonplaceholder.typicode.com/posts/3',
];
foreach ($urls as $url) {
Timer::add(0, function () use ($client, $url) {
$response = $client->get($url);
echo "Response received: " . $response->getBody() . PHP_EOL;
});
}
};
Worker::runAll();
解释:
- 使用
GuzzleHttp\Client
执行 HTTP 请求。 - 借助 Workerman 的定时器功能,模拟异步操作。
对比 ReactPHP 与 Workerman
特性 | ReactPHP | Workerman |
---|---|---|
模型 | 异步事件驱动 | 多进程+异步 I/O |
主要用途 | 异步操作、实时应用(WebSocket、HTTP 客户端) | 高并发网络服务(WebSocket、长连接、定时任务) |
并发处理 | 单进程内异步操作 | 多进程并发处理 |
易用性 | 更贴近异步编程模型 | 更贴近 PHP 的传统编程模型 |
性能 | 适合轻量级异步任务 | 更适合高并发、高 I/O 场景 |
总结
- ReactPHP 更适合需要复杂异步任务(比如 HTTP 客户端、文件读写)的场景,在单进程内实现类似多线程的效果。
- Workerman 更适合需要处理高并发连接(如 WebSocket 服务器、API 服务)的场景,通过多进程实现并发。
两者各有所长,具体选择取决于你的应用需求。