asyncio.gather()需传入未await的协程对象,否则报TypeError;默认一异常即中断所有任务,加return_exceptions=True可获混合结果;区别于create_task()+wait()在于高层封装、不支持单任务取消;需用Semaphore控制并发防性能陷阱。

asyncio.gather() 怎么用才不卡死
它不会自动并发,必须传入的是已创建但未 await 的协程对象(coro),不是 await 后的值,也不是普通函数调用。传错会立刻报 TypeError: an asyncio.Future, a coroutine or an awaitable is required。
- ✅ 正确:
asyncio.gather(coro1(), coro2(), coro3()) - ❌ 错误:
asyncio.gather(await coro1(), await coro2())(语法错误) - ❌ 错误:
asyncio.gather(coro1, coro2)(传了函数对象,没调用) - ❌ 错误:
asyncio.gather(coro1(), sync_func())(混入同步调用,阻塞整个事件循环)
asyncio.gather() 失败时返回什么
默认只要有一个协程抛异常,asyncio.gather() 就立刻中断其余运行中的任务,并把异常向上抛出——你拿不到其他已完成协程的结果。这不是“收集全部”,而是“全或无”。
- 想拿到所有结果(包括失败项),加参数
return_exceptions=True - 此时失败协程对应位置是
Exception实例,不是崩溃 - 注意:即使加了该参数,已启动但尚未完成的协程仍会被取消(取决于调度时机)
- 示例:
results = await asyncio.gather(coro_a(), coro_b(), return_exceptions=True)→results是混合了str、ValueError、TimeoutError的列表
asyncio.gather() 和 asyncio.create_task() + asyncio.wait() 有什么区别
asyncio.gather() 是高层封装,适合“等全部完成并收结果”的场景;create_task() + wait() 更底层,适合需要控制生命周期、响应部分完成、或做取消/超时精细管理的场合。
-
gather()内部确实用了create_task(),但它隐藏了 task 对象,无法单独 cancel 某个子任务 - 如果某个协程耗时极长,而你只想等前 N 个完成,
gather()不支持,得用asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) -
gather()在 Python 3.11+ 支持task_group风格的上下文管理(通过async with asyncio.TaskGroup()),但那是另一套 API,和gather()并不等价
asyncio.gather() 有性能陷阱吗
有。最大并发数不受控时,可能瞬间发起成百上千个 HTTP 请求或数据库连接,触发服务端限流、本地文件描述符耗尽、或内存暴涨。
立即学习“Python免费学习笔记(深入)”;
- 别直接把大列表喂给
gather(),尤其在爬虫或批量 IO 场景下 - 用
asyncio.Semaphore限制并发数:sem = asyncio.Semaphore(10) async def limited_coro(url): async with sem: return await fetch(url) results = await asyncio.gather(*[limited_coro(u) for u in urls]) - 注意:Python 3.11+ 的
asyncio.to_thread()不适用于gather()中混入 CPU 密集型操作——那会拖慢整个事件循环,应改用loop.run_in_executor()
return_exceptions=True 和并发数控制,这两个点一旦出问题,表现往往是“程序莫名退出”或“请求全挂掉但没报错”。










