parallel 函数返回 promise 对象而非直接结果,需在协程中 await 才能获取按输入顺序排列的结果数组;任一任务异常将导致整体失败,且闭包内须使用异步 io。

parallel 函数的返回值是 Promise 对象,不是直接结果
Hyperf 的 parallel 函数(来自 hyperf/utils)本质是并发执行协程任务,它**不阻塞等待**,而是立即返回一个 Promise 实例。如果你直接打印或使用返回值,看到的是 Hyperf\Utils\Coroutine\Parallel 对象或类似 Co\Channel 封装体,而不是你函数里 return 的数据。
必须 await 或协程内 yield 才能拿到真实返回值
在协程上下文中(比如控制器方法、Command 类、或已用 go 包裹的函数),你要用 await 解包 Promise:
// ✅ 正确:在协程函数中 await
public function index()
{
$results = await parallel([
fn() => sleep(1) && 'task1',
fn() => sleep(2) && 'task2',
]);
// $results 是 ['task1', 'task2'] 数组
}
常见错误包括:
- 在非协程环境(如普通 PHP CLI 脚本未启动 event loop)调用
await→ 报错Cannot use 'await' outside of a coroutine - 忘记
await,直接对parallel(...)结果做foreach→ 遍历的是 Promise 对象,不是数组 - 混用
go和parallel:二者都调度协程,但parallel本身已封装调度逻辑,外层再go会导致嵌套 Promise,徒增复杂度
parallel 返回数组顺序严格对应输入闭包顺序
即使第 2 个任务执行更快,parallel 保证返回数组索引 0 对应第一个闭包的返回值,索引 1 对应第二个——这点和 JavaScript 的 Promise.all 一致,但容易被误认为“按完成顺序返回”。
如果需要按完成先后收集结果,得自己用 Channel 或 Co\WaitGroup 手动实现,parallel 不提供该模式。
错误处理需统一 try/catch,单个任务异常会中断整个 parallel
parallel 默认行为是“全成功才返回”,任一闭包抛出异常(包括 throw new RuntimeException 或协程被 kill),整个 parallel 调用就会失败,返回的 Promise 被 reject。你必须在外层 try/catch 捕获:
try {
$results = await parallel([
fn() => throw new Exception('boom'),
fn() => 'ok',
]);
} catch (\Throwable $e) {
// $e 是第一个闭包抛出的异常
// $results 不会存在
}
若需忽略单个失败、继续收集其余结果,得改用 go + Channel 手动控制,或者给每个闭包包一层 try/catch 返回 ['error' => ..., 'result' => null] 结构。
最常被忽略的一点:parallel 的闭包里不能有阻塞 IO(如 file_get_contents、同步 cURL),否则会卡住整个协程调度;必须用 Hyperf 封装的异步客户端(HttpClient)、或 Co\run 内部的协程化 API。否则你以为在并发,其实只是串行假象。











