在 Python 的 asyncio
模块中,await asyncio.gather(*tasks)
和 await asyncio.wait(task_list)
都用于等待多个异步任务完成,但它们在功能、用法和行为上有一些细微的区别。下面我会详细解释它们的不同之处。
1. asyncio.gather(*tasks)
asyncio.gather(*tasks)
是一个非常常用的方法,用于并发执行多个异步任务,并等待它们全部完成。它会返回一个结果列表,其中每个元素对应每个任务的返回值。如果某个任务抛出了异常,gather()
会立即抛出异常,且会在所有任务中传播异常。
特点
- 返回值: 如果所有任务成功完成,
gather()
返回一个包含每个任务结果的列表。 - 异常传播: 如果某个任务抛出了异常,
gather()
会立刻抛出该异常,并且不会返回其他任务的结果,除非在捕获异常的上下文中处理它。 - 顺序保证: 返回的结果列表的顺序与任务传入的顺序一致,即使任务的执行顺序不同,返回值的顺序也会与传入时的顺序一致。
示例
import asyncioasync def task1():await asyncio.sleep(1)return "Task 1 complete"async def task2():await asyncio.sleep(2)return "Task 2 complete"async def main():results = await asyncio.gather(task1(), task2())print(results) # ['Task 1 complete', 'Task 2 complete']asyncio.run(main())
如果某个任务抛出异常,gather()
会立刻传播该异常。
async def task1():await asyncio.sleep(1)return "Task 1 complete"async def task2():await asyncio.sleep(2)raise ValueError("Task 2 failed!")async def main():try:results = await asyncio.gather(task1(), task2())except Exception as e:print(f"Error: {e}")asyncio.run(main()) # Output: Error: Task 2 failed!
2. asyncio.wait(task_list)
asyncio.wait(task_list)
是一个低级的 API,用于等待一个任务集合中的任务完成。它返回一个包含两组任务的元组:一组是已经完成的任务,另一组是仍然未完成的任务。wait()
更加灵活,可以用于控制任务的执行状态,但它并不会返回任务的结果。
特点
- 返回值: 返回一个二元组
(done, pending)
,其中done
是已完成的任务,pending
是仍然在等待的任务。done
和pending
都是set
类型。 - 异常处理:
asyncio.wait()
不会自动抛出异常。你需要单独处理任务中的异常。 - 可自定义行为:
asyncio.wait()
允许你设置如何等待任务完成,比如设置timeout
或者通过return_when
参数来控制如何完成等待(例如:asyncio.FIRST_COMPLETED
、asyncio.FIRST_EXCEPTION
)。
示例
import asyncioasync def task1():await asyncio.sleep(1)return "Task 1 complete"async def task2():await asyncio.sleep(2)return "Task 2 complete"async def main():tasks = [task1(), task2()]done, pending = await asyncio.wait(tasks)# 查看已经完成的任务for task in done:print(task.result()) # Output: Task 1 complete / Task 2 completeasyncio.run(main())
asyncio.wait()
的更多控制
asyncio.wait()
提供了额外的控制选项,通过 return_when
参数,你可以选择等待所有任务完成或等待第一个任务完成。
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
asyncio.FIRST_COMPLETED
:返回第一个完成的任务。asyncio.FIRST_EXCEPTION
:返回第一个抛出异常的任务。asyncio.ALL_COMPLETED
:等待所有任务完成(这是默认行为)。
主要区别
特性 | asyncio.gather(*tasks) |
asyncio.wait(task_list) |
---|---|---|
返回值 | 返回任务的结果列表。 | 返回二元组 (done, pending) ,分别是已完成的任务和未完成的任务。 |
异常处理 | 如果有任务抛出异常,gather 会立刻抛出异常,其他任务的结果不会返回。 |
需要手动处理任务的异常。 |
任务顺序 | 返回的结果顺序与传入任务的顺序一致。 | 不保证顺序。 |
控制选项 | 没有 return_when 选项,等待所有任务完成。 |
提供 return_when 参数,允许等待某个特定的任务状态。 |
适用场景 | 用于需要获取所有任务结果并且确保任务按顺序完成的情况。 | 用于需要更细粒度控制任务执行过程(如超时、等待第一个完成等)的情况。 |
总结
asyncio.gather()
是一个更高级的、用于等待任务完成并收集结果的方法,适合于需要获取所有任务结果并保证顺序的情况。asyncio.wait()
提供更多控制和灵活性,适合于需要精确控制任务执行顺序、等待任务完成状态或需要处理任务异常的情况。
选择哪个方法取决于你的需求:
- 如果你只需要等待任务完成并获取结果,使用
gather()
更简单。 - 如果你需要更多控制(比如超时、处理异常或等待第一个任务完成),则使用
wait()
。