使用asyncio启动同步后台任务,能否实现六任务并发运行?
问题解答
首先得先修正你代码里的几个语法错误,不然根本跑不起来:
functools.partial(foo2(), i)这里错把foo2的调用结果传给了partial,应该直接传foo2函数本身,改成functools.partial(foo2, i)await asyncio.wait_for(...)的括号不匹配,缺少右括号main函数里没有等待所有后台任务完成的逻辑,会导致程序直接退出,任务还没执行完
修正后的代码大概是这样:
import asyncio import functools import time def foo2(num): # 模拟阻塞代码,比如休眠2秒 print(f"任务 {num} 开始执行") time.sleep(2) print(f"任务 {num} 执行完成") return num async def foo1(i): loop = asyncio.get_running_loop() try: await asyncio.wait_for( loop.run_in_executor(None, functools.partial(foo2, i)), timeout=60 ) except asyncio.TimeoutError: print(f"任务 {i} 超时") async def main(): background_t = set() for i in range(6): task = asyncio.create_task(foo1(i)) background_t.add(task) # 等待所有后台任务完成 await asyncio.gather(*background_t) if __name__ == '__main__': asyncio.run(main())
回到你的问题:这种修正后的模式是可以让六个同步阻塞任务实现并发运行的。
原因很简单:
loop.run_in_executor默认会使用ThreadPoolExecutor,把同步阻塞的foo2提交到线程池的线程里执行- 每个
foo1任务在调用await loop.run_in_executor(...)时,会把控制权交还给asyncio事件循环,事件循环可以调度其他foo1任务执行,进而把对应的foo2也提交到线程池 - 线程池里的多个线程会并行执行这些
foo2阻塞任务,最终实现六个任务的并发运行
你可以跑一下上面的修正代码,会看到六个任务几乎同时开始,2秒左右全部完成,而不是串行执行需要12秒,这就证明了并发效果。
内容的提问来源于stack exchange,提问作者JavaSa
相关产品推荐
相关产品推荐

