如何在asyncio的gather集合中动态添加新协程且避免阻塞原有协程?
在asyncio中动态添加协程到调度队列的实现方案
可行,但asyncio.gather()无法支持动态添加协程(它接收固定的任务集合,启动后无法新增),需要改用以下两种方式实现:
方案一:使用asyncio.TaskGroup(Python 3.11+ 推荐)
TaskGroup是Python 3.11引入的特性,原生支持在运行过程中动态添加任务,且自动等待所有任务完成,无需手动管理任务生命周期。
示例代码:
import asyncio async def pingLoop(task_group): print("pingLoop 启动") # 模拟循环执行的异步阻塞操作 for i in range(5): await asyncio.sleep(1) print(f"pingLoop 执行第 {i+1} 次") # 在第3次循环时动态添加新协程 if i == 2: print("添加 pingSpecial 任务") # 调用TaskGroup的create_task添加任务,不会阻塞当前协程 task_group.create_task(pingSpecial()) print("pingLoop 结束") async def pingSpecial(): print("pingSpecial 启动") await asyncio.sleep(2) print("pingSpecial 结束") async def main(): async with asyncio.TaskGroup() as tg: # 初始化添加pingLoop任务 tg.create_task(pingLoop(tg)) print("所有任务执行完成") asyncio.run(main())
方案二:手动维护任务集合(兼容Python 3.7+)
如果使用低版本Python,可通过asyncio.create_task()创建任务,用集合维护任务列表,配合asyncio.wait()等待所有任务完成。
示例代码:
import asyncio async def pingLoop(tasks): print("pingLoop 启动") for i in range(5): await asyncio.sleep(1) print(f"pingLoop 执行第 {i+1} 次") if i == 2: print("添加 pingSpecial 任务") # 创建新任务并加入集合 new_task = asyncio.create_task(pingSpecial()) tasks.add(new_task) # 任务完成后自动从集合移除,避免内存泄漏 new_task.add_done_callback(tasks.discard) print("pingLoop 结束") async def pingSpecial(): print("pingSpecial 启动") await asyncio.sleep(2) print("pingSpecial 结束") async def main(): tasks = set() # 初始化添加pingLoop任务 initial_task = asyncio.create_task(pingLoop(tasks)) tasks.add(initial_task) initial_task.add_done_callback(tasks.discard) # 等待集合中所有任务完成 await asyncio.wait(tasks) print("所有任务执行完成") asyncio.run(main())
内容的提问来源于stack exchange,提问作者Miro Krsjak
相关产品推荐
相关产品推荐

