必须用底层机制精确控制协程并发数:启动前通过$worker->eventLoopOptions预设上限;运行时可用Channel信号量或Barrier计数器限流;再按IO/CPU负载分层使用专属协程池并配置超时与拒绝策略。

在高并发场景下,协程数量失控会导致内存暴涨、调度延迟甚至服务崩溃,必须用底层机制实现精确控制而非依赖默认行为。
启动前预设协程并发上限
Workerman 5.0 使用 Revolt 事件循环时,默认不限制协程并发数。需在 Worker 初始化阶段显式配置:【$worker->eventLoopOptions = ['max_coroutines' => 100];】。该参数仅对 Revolt 驱动生效,Swoole 或 Swow 驱动需改用各自原生限制方式。
这一步必须放在 new Worker() 之后、runAll() 之前,否则无效。
运行时动态限制协程并发
方法一:使用 Channel 实现信号量式限流
创建容量为 N 的 Channel 作为“协程许可证池”:$semaphore = new Channel(5);。每次启动新协程前先 await $semaphore->pop();,执行完毕后 await $semaphore->push(true);。这能硬性卡死同时运行的协程不超过 5 个。
方法二:用 Barrier + 计数器软限流
定义全局计数器 static $running = 0; 和最大阈值 const MAX_CONCURRENT = 8;。在协程入口加锁判断:if (++$running > MAX_CONCURRENT) { await Coroutine::sleep(0.1); --$running; return; }。退出时 --$running;。注意:此法不防竞态,仅适合低频调用场景。
按业务类型分层控制协程资源
第一步:识别协程负载等级
IO 密集型(如 HTTP 请求、Redis 操作)可允许更高并发;CPU 密集型(如 JSON 解析、图像缩放)必须严格限制,否则会拖垮整个事件循环。
第二步:为不同业务绑定专属协程池
使用 Workerman\Pool\Pool 创建两个池:$io_pool = new Pool(20, 'io'); 和 $cpu_pool = new Pool(3, 'cpu');。调用时明确指定:await $io_pool->get()->httpGet(...); 或 await $cpu_pool->get()->processImage(...);。
第三步:设置池级超时与拒绝策略
初始化时传入选项:new Pool(5, 'cpu', ['timeout' => 2.0, 'reject_on_full' => true]);。当池满且 【reject_on_full = true】 时,直接抛出 PoolException,避免协程无限排队。

















