不会阻塞,但无并发效果;array_map是纯CPU同步操作,不触发协程挂起,需改用go()+WaitGroup+Channel实现可控并发。

协程里直接用 PHP array_map 会阻塞吗
不会阻塞,但也没并发效果。PHP 原生的 array_map 是同步函数,它只是遍历数组、逐个调用回调,在协程上下文中它不触发任何 I/O,也不会让出控制权——它就是纯 CPU 计算。你用 go() 包一层,也还是串行执行,因为没挂起点。
真正需要并发的场景,通常是「对每个元素发起网络请求、查 DB、读文件」这类 I/O 操作。这时候不能靠 array_map,得手动展开为协程任务。
- 错误写法:
array_map(fn($x) => $redis->get($x), $keys)—— 这会阻塞整个协程(除非已启用SWOOLE_HOOK_ALL且$redis是协程客户端) - 正确方向:用
go()+Channel或Swoole\Coroutine\WaitGroup控制并发粒度
如何实现可控并发的 map-like 操作
没有内置的「协程版 array_map」,但可以用几行代码模拟,关键是控制并发数、收集结果、处理异常。
示例:对 1000 个 key 并发查 Redis,最多同时跑 10 个协程:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
// 创建容量为 10 的 Channel 作信号量
$sem = new Swoole\Coroutine\Channel(10);
for ($i = 0; $i < 10; $i++) {
$sem->push(true);
}
$results = [];
$wg = new Swoole\Coroutine\WaitGroup();
$wg->add(count($keys));
foreach ($keys as $key) {
go(function () use ($key, $redis, $sem, $wg, &$results) {
$sem->pop(); // 获取一个并发槽位
try {
$results[$key] = $redis->get($key);
} catch (Throwable $e) {
$results[$key] = null;
} finally {
$sem->push(true); // 归还槽位
$wg->done();
}
});
}
$wg->wait();
- 不用
Channel也能做,但容易把协程数打满,压垮连接池或远端服务 - 别用
array_walk或foreach直接套go()——没节流,max_coroutine超限会报错或静默失败 - 结果顺序不保证,如需保序,改用索引键存结果,最后按原数组顺序重组
为什么开了 enable_coroutine 还是慢?检查这三个点
常见假象:配置写了 enable_coroutine = true,但实际没生效,或被其他配置抵消。
-
Swoole\Runtime::enableCoroutine()必须在Server->start()之前调用,且推荐传SWOOLE_HOOK_ALL;只设enable_coroutine = true在set()里不够 -
worker_num设太高(比如 32)+enable_coroutine = true→ 多余进程争抢事件循环,CPU 空转、延迟飙升 - 用了传统
PDO或cURL同步客户端 → 即使开了协程,I/O 仍阻塞,整个 worker 卡死
最稳的组合是:worker_num = 1~4、max_coroutine = 3000~10000(按内存预留)、Swoole\Runtime::enableCoroutine(SWOOLE_HOOK_ALL),再配协程 Redis/MySQL 客户端。
map 操作中 DB 连接复用的坑
协程间不能共享数据库连接对象。一个 Swoole\Coroutine\MySQL 实例只能被一个协程安全使用。
- 错误:创建一个全局
$db,所有协程都调$db->query()→ 数据错乱、连接断开、返回空结果 - 正确:用连接池,每次从池里
pop()一个连接,用完push()回去;或者每协程新建连接(开销略高但简单) - 注意:连接池 size 要 ≥ 并发协程数,否则
pop()会阻塞,等同于串行
连接池不是银弹——如果单次查询本身慢(比如没走索引),并发再多也救不了。先优化 SQL,再上并发。

















