一、一句话区分

  • WaitGroup = “计数器闩锁”:事先知道要启动多少子协程,主协程等它们 全部跑完 再往下走;不传递数据,只同步“结束”事件。
  • Channel = “内存队列”:事先 不知道 子协程数量或需要收发数据,协程间 push/pop 消息;既能同步又能通信

二、WaitGroup 详解

  1. 原理:内部维护一个 countadd(n)count+=n;每个子协程 done()count-=1wait()count>0 时阻塞,底层就是 Channel->pop()
  2. 场景:并发任务数量确定,只需“全部完成”信号。
  3. 示例:并发爬 3 个网页,全部返回后统一输出。
use Swoole\Coroutine;
use Swoole\Coroutine\WaitGroup;

run(function () {
    $wg = new WaitGroup();
    $results = [];

    foreach (['baidu', 'taobao', 'qq'] as $site) {
        $wg->add();                                    // 计数 +1
        Coroutine::create(function () use ($wg, &$results, $site) {
            $results[$site] = file_get_contents("https://$site.com");
            $wg->done();                               // 计数 -1
        });
    }

    $wg->wait();                                       // 全部 done 才继续
    echo "全部抓取完成,共 " . count($results) . " 条\n";
});

三、Channel 详解

  1. 原理:协程级多生产者-多消费者队列;满时 push() 自动让出 CPU,空时 pop() 自动让出 CPU;可设置容量,也可传任意 PHP 值(零拷贝)。
  2. 场景:
    • 数据流管道:生产者不断生成,消费者一边处理一边消费;
    • 并发数量未知:用“结束哨兵”通知消费者退出;
    • 连接池/任务池:把可用连接或任务塞进 Channel,工作协程 pop() 获取。
  3. 示例:未知数量任务流式处理。
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;

run(function () {
    $chan = new Channel(10);          // 缓冲区 10

    // 3 个生产者
    for ($i = 0; $i < 3; $i++) {
        Coroutine::create(function () use ($chan, $i) {
            foreach (range(1, 5) as $v) {
                $chan->push("任务-$i-$v");
                Coroutine::sleep(0.1); // 模拟 IO
            }
            $chan->push(null);        // 本生产者结束哨兵
        });
    }

    // 2 个消费者
    for ($i = 0; $i < 2; $i++) {
        Coroutine::create(function () use ($chan, $i) {
            while (1) {
                $task = $chan->pop();  // 无任务自动挂起
                if ($task === null) break;
                echo "消费者 $i 处理 $task\n";
            }
        });
    }
});

四、对照表

维度 WaitGroup Channel
核心功能 同步“全部完成” 消息队列 + 同步
数据传递 ✅(任意 PHP 值)
子协程数量 必须事先知道 可动态/未知
典型场景 并发请求、批量写入 流式处理、连接池、任务队列
实现原理 内部用 Channel 做计数阻塞 底层无锁队列 + yield/resume

五、一句话总结

  • 只要“等全部跑完”→ WaitGroup
  • 还要“收发数据”或“数量未知”→ Channel
  • WaitGroup 底层就是 对 Channel 的轻量级封装,二者常配合使用。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐