Python 3.6中使用async for实现HTTP请求同时执行的问题
如何用asyncio实现多个HTTP请求的并发执行?
你当前的代码之所以是串行执行,问题出在**async for的工作方式**上:它会逐个遍历异步生成器的每一次yield,并且每次都会等待当前迭代里的await操作完成后,才会进入下一次循环。所以你的ticker生成器每次只能跑一个循环,自然是顺序输出的。
要实现真正的并发,我们需要把每个请求(或者每个独立的异步任务)包装成asyncio.Task,让事件循环同时调度这些任务,而不是逐个等待。下面给你两种可行的实现方式:
方式一:直接创建任务并批量等待
这是最直观的写法,适合明确知道要创建多少个任务的场景:
import asyncio # 这里替换成你实际的aiohttp请求逻辑 async def fetch_data(delay, task_id): print(f"启动任务 {task_id}") await asyncio.sleep(delay) # 模拟HTTP请求耗时 print(f"任务 {task_id} 执行完成") return f"任务 {task_id} 的返回结果" async def main(): # 创建3个并发任务,每个任务延迟1秒 task_list = [ asyncio.create_task(fetch_data(1, 0)), asyncio.create_task(fetch_data(1, 1)), asyncio.create_task(fetch_data(1, 2)) ] # 等待所有任务完成,同时收集结果 all_results = await asyncio.gather(*task_list) print("所有任务执行完毕,结果:", all_results) if __name__ == "__main__": asyncio.run(main())
这段代码的输出会是:
启动任务 0 启动任务 1 启动任务 2 任务 0 执行完成 任务 1 执行完成 任务 2 执行完成 所有任务执行完毕,结果: ['任务 0 的返回结果', '任务 1 的返回结果', '任务 2 的返回结果']
关键说明:
asyncio.create_task()会把异步函数立即加入事件循环调度,不需要等待await就会开始执行asyncio.gather(*task_list)会阻塞直到所有任务完成,并且按顺序返回每个任务的结果
方式二:用异步生成器批量创建任务
如果你需要通过生成器来动态生成任务(比如从列表/数据库里读取请求参数),可以用异步生成器配合列表推导式来创建任务,再批量等待:
import asyncio async def fetch_data(delay, task_id): print(f"启动任务 {task_id}") await asyncio.sleep(delay) print(f"任务 {task_id} 执行完成") return f"任务 {task_id} 的返回结果" # 异步生成器,用来批量生成任务 async def generate_tasks(total_tasks, delay): for task_id in range(total_tasks): yield asyncio.create_task(fetch_data(delay, task_id)) async def main(): # 从生成器里收集所有任务 task_list = [task async for task in generate_tasks(3, 1)] # 等待所有任务完成 all_results = await asyncio.gather(*task_list) print("所有任务执行完毕,结果:", all_results) if __name__ == "__main__": asyncio.run(main())
这种写法的效果和方式一完全一样,但更适合动态生成任务的场景。
核心要点总结
async for本身是串行迭代工具,它的作用是逐个处理异步生成器的输出,不是用来实现并发的- 实现并发的核心是创建多个独立的
Task对象,让asyncio的事件循环同时调度它们 - 用
asyncio.gather()或asyncio.wait()来统一等待所有并发任务完成,避免遗漏任务状态
内容的提问来源于stack exchange,提问作者YYY
相关产品推荐
相关产品推荐

