Python的asyncio模块提供了丰富的异步编程工具,其中as_completed函数用于并发运行多个可等待对象,并按照完成顺序返回结果,是处理多协程并发场景的常用方法,掌握其使用规范能有效提升异步代码的可靠性。

asyncio.as_completed 基本定义
asyncio.as_completed是asyncio模块的内置函数,接收一个可等待对象列表作为参数,返回一个异步迭代器,迭代器会按照每个可等待对象的完成顺序依次产出对应的结果。它的核心作用是让开发者可以在多个协程并发执行时,不需要等待所有协程全部完成再处理结果,而是哪个协程先完成就先处理哪个的结果,提升整体执行效率。
核心使用规范
1. 参数传递规范
as_completed的第一个参数必须是可迭代的可等待对象集合,通常是协程对象列表,第二个可选参数是timeout,用于设置整体超时时间,单位为秒。需要注意传入的协程对象必须是未执行的,也就是不要提前调用协程函数获取结果后再传入。
正确的参数传递示例如下:
import asyncio
async def task(name, delay):
await asyncio.sleep(delay)
return f"任务{name}完成,耗时{delay}秒"
async def main():
# 创建未执行的协程对象列表
tasks = [task(f"task_{i}", i) for i in range(3)]
# 传入as_completed
for coro in asyncio.as_completed(tasks, timeout=5):
try:
result = await coro
print(result)
except asyncio.TimeoutError:
print("任务超时")
asyncio.run(main())
2. 结果获取规范
as_completed返回的是异步迭代器,每个元素是一个可等待对象,必须通过await获取最终结果,不能直接将其当作结果使用。如果某个协程执行过程中抛出异常,await对应元素时会将异常抛出,因此需要使用try-except块捕获可能的异常,避免程序崩溃。
错误的结果获取方式示例:
# 错误示例:直接打印迭代器元素,不会得到实际结果
for item in asyncio.as_completed(tasks):
print(item) # 输出的是可等待对象,不是任务结果
3. 超时处理规范
如果设置了timeout参数,当超过指定时间仍有协程未完成时,as_completed的迭代器会抛出asyncio.TimeoutError异常,需要在迭代过程中捕获该异常,处理超时场景下的逻辑,比如记录超时任务、释放资源等。
4. 协程状态规范
传入as_completed的协程对象必须是独立的,不要重复使用同一个协程对象,也不要在传入后修改协程对象的状态,否则会导致不可预期的执行结果。如果需要重复执行相同逻辑的任务,应该每次都创建新的协程对象。
常见错误用法
- 提前执行协程再传入:有些开发者会先调用协程函数并await后再传入as_completed,这会导致协程已经执行完毕,失去了并发的意义。
- 忽略异常处理:没有捕获协程执行过程中的异常和超时异常,导致程序在遇到错误时直接退出。
- 错误理解返回顺序:误以为as_completed会按照传入列表的顺序返回结果,实际上它是严格按照协程完成的先后顺序返回。
实际应用场景
as_completed非常适合多个独立任务并发执行,且需要优先处理先完成结果的场景,比如同时请求多个接口,哪个接口先返回数据就先处理哪个,不需要等待所有接口都返回再统一处理。以下是一个多接口请求的示例:
import asyncio
import random
async def fetch_api(api_name):
# 模拟接口请求耗时,随机1-5秒
delay = random.randint(1, 5)
await asyncio.sleep(delay)
# 模拟接口可能失败的情况
if random.random() < 0.2:
raise Exception(f"{api_name}请求失败")
return f"{api_name}请求成功,耗时{delay}秒"
async def main():
api_list = ["用户接口", "订单接口", "商品接口", "支付接口"]
tasks = [fetch_api(api) for api in api_list]
for coro in asyncio.as_completed(tasks, timeout=10):
try:
result = await coro
print(result)
except Exception as e:
print(f"捕获到异常:{e}")
except asyncio.TimeoutError:
print("整体请求超时")
asyncio.run(main())
注意事项总结
使用asyncio.as_completed时,务必保证传入的是未执行的协程对象列表,通过await获取每个迭代元素的结果,做好异常和超时的捕获处理,不要依赖返回结果的顺序,根据实际场景合理设置超时时间,才能充分发挥该方法的并发处理优势。
asyncioas_completedPython异步编程协程并发控制修改时间:2026-07-09 06:21:29