在 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

特性ReactPHPWorkerman
模型异步事件驱动多进程+异步 I/O
主要用途异步操作、实时应用(WebSocket、HTTP 客户端)高并发网络服务(WebSocket、长连接、定时任务)
并发处理单进程内异步操作多进程并发处理
易用性更贴近异步编程模型更贴近 PHP 的传统编程模型
性能适合轻量级异步任务更适合高并发、高 I/O 场景

总结

  • ReactPHP 更适合需要复杂异步任务(比如 HTTP 客户端、文件读写)的场景,在单进程内实现类似多线程的效果。
  • Workerman 更适合需要处理高并发连接(如 WebSocket 服务器、API 服务)的场景,通过多进程实现并发。

两者各有所长,具体选择取决于你的应用需求。

标签: PHP, ReactPHP, Workerman

添加新评论