本文目录导读:

- 使用 Swoole 的 Coroutine\WaitGroup
- 使用 Swoole 的 Channel 模拟
- 使用 Fiber(PHP 8.1+)实现
- 使用 ReactPHP 的 Promise
- 自定义简单的协程等待组
- 建议
在 PHP 中实现协程等待组(类似 Go 的 sync.WaitGroup),可以使用 Swoole 或 Fiber 扩展,以下是几种实现方式:
使用 Swoole 的 Coroutine\WaitGroup
Swoole 提供了内置的 WaitGroup 类:
<?php
use Swoole\Coroutine;
use Swoole\Coroutine\WaitGroup;
$waitGroup = new WaitGroup();
// 启动 3 个协程
for ($i = 0; $i < 3; $i++) {
$waitGroup->add(); // 计数器 +1
Coroutine::create(function () use ($waitGroup, $i) {
try {
// 模拟异步任务
Coroutine::sleep(rand(1, 3));
echo "Task {$i} completed\n";
} finally {
$waitGroup->done(); // 计数器 -1
}
});
}
// 等待所有协程完成
$waitGroup->wait();
echo "All tasks completed\n";
使用 Swoole 的 Channel 模拟
<?php
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
$channel = new Channel(10);
$taskCount = 3;
for ($i = 0; $i < $taskCount; $i++) {
Coroutine::create(function () use ($channel, $i) {
Coroutine::sleep(rand(1, 3));
echo "Task {$i} completed\n";
$channel->push(true); // 发送完成信号
});
}
// 等待所有任务完成
for ($i = 0; $i < $taskCount; $i++) {
$channel->pop();
}
echo "All tasks completed\n";
使用 Fiber(PHP 8.1+)实现
<?php
class FiberWaitGroup {
private int $count = 0;
private array $waiters = [];
public function add(int $delta = 1): void {
$this->count += $delta;
}
public function done(): void {
$this->count--;
if ($this->count === 0) {
// 唤醒所有等待的 Fiber
foreach ($this->waiters as $waiter) {
if (!$waiter->isTerminated()) {
$waiter->resume();
}
}
$this->waiters = [];
}
}
public function wait(): void {
if ($this->count === 0) {
return;
}
$this->waiters[] = Fiber::this();
Fiber::suspend();
}
}
// 使用示例
function asyncTask(int $id, FiberWaitGroup $wg): void {
Fiber::suspend(); // 模拟异步操作
echo "Task {$id} completed\n";
$wg->done();
}
$wg = new FiberWaitGroup();
$fibers = [];
for ($i = 0; $i < 3; $i++) {
$wg->add();
$fiber = new Fiber(function () use ($i, $wg) {
asyncTask($i, $wg);
});
$fibers[] = $fiber;
$fiber->start();
}
// 等待所有 Fiber 完成
$wg->wait();
echo "All tasks completed\n";
使用 ReactPHP 的 Promise
虽然不是协程,但也能实现类似功能:
<?php
require 'vendor/autoload.php';
use React\EventLoop\Factory;
use React\Promise\Promise;
$loop = Factory::create();
function asyncTask(int $id, $loop): Promise {
return new Promise(function ($resolve) use ($id, $loop) {
$loop->addTimer(rand(1, 3), function () use ($id, $resolve) {
echo "Task {$id} completed\n";
$resolve(true);
});
});
}
$tasks = [];
for ($i = 0; $i < 3; $i++) {
$tasks[] = asyncTask($i, $loop);
}
\React\Promise\all($tasks)->then(function () {
echo "All tasks completed\n";
$this->loop->stop();
});
$loop->run();
自定义简单的协程等待组
<?php
use Swoole\Coroutine;
class SimpleWaitGroup {
private int $count = 0;
private array $waitingFns = [];
public function add(): void {
$this->count++;
}
public function done(): void {
$this->count--;
if ($this->count === 0 && !empty($this->waitingFns)) {
foreach ($this->waitingFns as $fn) {
$fn();
}
$this->waitingFns = [];
}
}
public function wait(callable $onComplete): void {
if ($this->count === 0) {
$onComplete();
return;
}
$this->waitingFns[] = $onComplete;
}
}
// 使用示例
$wg = new SimpleWaitGroup();
$wg->add();
Coroutine::create(function () use ($wg) {
Coroutine::sleep(1);
echo "Task 1\n";
$wg->done();
});
$wg->add();
Coroutine::create(function () use ($wg) {
Coroutine::sleep(2);
echo "Task 2\n";
$wg->done();
});
$wg->wait(function () {
echo "All tasks completed\n";
});
建议
- 生产环境推荐使用 Swoole,它是最成熟、性能最好的 PHP 协程方案
- PHP 8.1+ 可以使用 Fiber,但功能相对基础
- 记得处理异常,确保
done()一定被调用(使用finally) - 避免在协程中执行阻塞操作,否则会阻塞整个事件循环
选择哪种方案取决于你的项目需求和运行环境。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播