Python中关于asyncio.gather()的问题与使用
loop = asyncio.get_event_loop()
exerciseId = [1,2,3]
// once 为协程
tasks = [once(i) for i in exerciseId]
loop.run_until_complete(asyncio.gather(*tasks))
Expected: 执行顺序是 once(1),once(2),once(3)
In fact: 是无序的,譬如是 2,3,1 的顺序
于是去查看 asyncio.gather 源码的时候,发现这么一行代码:for arg in set(coros_or_futures):。这个函数对列表 tasks 先进行了一次 set()操作,而 set 在 python 里是通过 hash 实现的,所以导致的无序是么?
那现在我希望按列表里的顺序进行添加 Task 操作,有什么好的办法呢?
Python中关于asyncio.gather()的问题与使用
同步运行就有顺序了?
asyncio.gather() 是 asyncio 模块里用来并发运行多个异步任务的核心函数。简单来说,它接收一堆协程(coroutine)或任务(Task),然后同时启动它们,最后等所有任务都完成,把结果收集到一个列表里返回。
基本用法:
import asyncio
async def task1():
await asyncio.sleep(1)
return "任务1完成"
async def task2():
await asyncio.sleep(2)
return "任务2完成"
async def main():
# 同时运行 task1 和 task2
results = await asyncio.gather(task1(), task2())
print(results) # 输出: ['任务1完成', '任务2完成']
asyncio.run(main())
这里 task1 和 task2 会并发执行,总共耗时约2秒(而不是3秒)。
关键点:
- 返回值顺序:
gather()返回的结果列表顺序严格对应你传入任务的顺序,和哪个任务先完成无关。 - 错误处理:
- 默认情况下,如果任何一个任务抛出异常,
gather()会立即抛出那个异常,其他任务会被取消。 - 设置
return_exceptions=True可以让异常作为结果返回,而不是中断整个操作。
async def faulty_task(): raise ValueError("出错了") async def main(): results = await asyncio.gather( task1(), faulty_task(), task2(), return_exceptions=True # 异常会变成结果的一部分 ) print(results) # 输出: ['任务1完成', ValueError('出错了'), '任务2完成'] - 默认情况下,如果任何一个任务抛出异常,
- 传入的是协程对象:记住要把协程函数调用(如
task1())传进去,而不是函数本身(task1)。
常见坑:
- 如果你在
gather()里直接传了一个已经创建但未await的协程对象,它可能不会按你预期的方式运行。通常直接传coro()就行。 - 想中途取消所有任务?直接取消
gather()返回的协程本身就行。
一句话总结:用 gather 来并发跑多个独立异步任务并收集结果,注意错误处理和传参方式。
如果想要按照顺序依次添加,那就依次实例化 asyncio.Task 就行了。
tasks = [asyncio.Task(once(i)) for i in exerciseId]
或者依次调用 ensure_future 也行,
tasks = [asyncio.ensure_future(once(i)) for i in exerciseId]
感谢~明天试试
不对。。今天
python 真是强行异步,晦涩啊
所有的异步都是增加逻辑负担的,所以最好的方式当然是同步的方式写异步
话说你用了协程这几个任务应该不需要有先后的依赖吧。
哦哦,不过 Python 协程用起来感觉真别扭


