如何使用Python的asyncio并行运行多个异步函数以缩短执行耗时
如何使用Python的asyncio并行运行多个异步函数以缩短执行耗时
嗨,我明白你的问题——现在你是逐个顺序执行这些异步函数,相当于把异步任务硬生生做成了同步流程,难怪要花50秒!其实异步的核心优势就是能并行处理IO密集型任务(比如你说的异步请求),用Python的asyncio模块就能轻松把这个耗时砍下来,我给你详细说说怎么做:
首先先纠正一下你原来代码里的小问题:如果get_functions_list里是异步函数,你原来的循环其实只是把协程对象添加到列表里,并没有真正执行它们——正确的顺序执行应该是要await每个函数的,比如原来的代码大概是这样:
async def main(): all_data = [] for func in get_functions_list: try: # 必须await才能执行异步函数并获取结果 result = await func() all_data.append(result) except: continue
这种写法会让每个异步函数等前一个完全执行完才开始,所以总耗时是所有函数耗时的总和,这完全浪费了异步的优势。
方法一:用asyncio.gather()批量并行执行(最推荐)
asyncio.gather()是专门用来批量运行多个异步任务的工具,它会让所有任务同时启动,并行处理,最后返回所有结果。而且可以通过参数优雅处理异常,避免单个任务失败影响全局。
示例代码:
import asyncio async def main(): # 先把所有异步函数转换成协程任务(如果get_functions_list是函数对象的话) tasks = [func() for func in get_functions_list] # 并行执行所有任务,return_exceptions=True让失败的任务返回异常而非直接崩溃 results = await asyncio.gather(*tasks, return_exceptions=True) # 过滤掉异常结果,收集成功的数据 all_data = [] for res in results: if not isinstance(res, Exception): all_data.append(res) print("最终收集的数据:", all_data) # 启动事件循环 asyncio.run(main())
为什么这个快?因为所有异步任务会同时开始执行,当某个任务在等待网络响应(或者其他IO操作)时,事件循环会自动切换到其他任务继续执行,所以总耗时会接近单个任务的最长耗时,而不是所有任务耗时相加——比如你原来50个任务每个1秒,现在并行后大概1秒就能完成!
方法二:用asyncio.create_task()手动创建并行任务
如果你需要更灵活地逐个处理任务(比如中途添加任务或者单独监控某个任务),可以用create_task()手动创建任务,然后统一等待它们完成:
import asyncio async def main(): tasks = [] # 先创建所有异步任务 for func in get_functions_list: task = asyncio.create_task(func()) tasks.append(task) all_data = [] # 逐个等待任务完成并处理结果 for task in tasks: try: result = await task all_data.append(result) except: continue print("最终收集的数据:", all_data) asyncio.run(main())
这种方法和gather()的效果类似,只是更灵活,适合需要对单个任务做特殊处理的场景。
几个重要的注意事项
- 确保你用的是真正的异步库:比如如果是网络请求,要用
aiohttp而不是同步的requests——同步库会阻塞事件循环,即使并行也没法提速。 return_exceptions=True的作用:如果某个任务抛出异常,gather()不会立刻终止所有任务,而是把异常作为对应位置的结果返回,方便你后续过滤;如果不用这个参数,只要有一个任务失败,整个gather()就会抛出异常,其他任务的结果也拿不到。- 确认
get_functions_list里的是异步函数:必须是用async def定义的函数,普通同步函数没法用asyncio并行,那时候得考虑用多进程/多线程。
备注:内容来源于stack exchange,提问作者Victor4897
相关产品推荐
相关产品推荐

