关于简单asyncio示例的理解误区与非阻塞代码修复请求
asyncio协程阻塞问题分析与修复
我有一个耗时8秒的IO任务放在协程task()中,想要实现无限循环,每5秒执行该任务且不阻塞主循环,但当前代码运行时主循环会被阻塞,输出不符合预期。
原代码
import asyncio async def task(): print('starting task') await asyncio.sleep(8) print('finished task') async def main(): count = 0 while True: print(count) if count % 5 == 0: print('running task') await task() count += 1 await asyncio.sleep(1) asyncio.run(main())
当前输出
0 running task starting task finished task 1 2 3 4 5 running task starting task finished task 6 7 8 9 10
错误原因
你误解了await的作用:当在main里await task()时,main协程会暂停执行,直到task协程完全运行结束。哪怕task里有await asyncio.sleep(8),这只是让task暂时让出控制权给事件循环,但main因为在等待task的结果,所以不会继续往下执行,直到task的sleep完成、整个task结束后,main才会继续计数和睡眠。
修复方案
要让task在后台运行不阻塞main,需要用asyncio.create_task()将协程包装成一个后台任务,这样事件循环会调度它运行,而main不需要等待它完成,可以继续执行自己的逻辑。
修改后的代码
import asyncio async def task(): print('starting task') await asyncio.sleep(8) print('finished task') async def main(): count = 0 while True: print(count) if count % 5 == 0: print('running task') # 用create_task创建后台任务,不阻塞main asyncio.create_task(task()) count += 1 await asyncio.sleep(1) asyncio.run(main())
修复后输出示例
0 running task starting task 1 2 3 4 5 running task starting task 6 7 8 finished task 9 10 starting task ...
可以看到,主循环的计数不会被阻塞,task在后台运行,8秒后输出finished task,同时主循环继续正常执行。
内容的提问来源于stack exchange,提问作者AndrewK
相关产品推荐
相关产品推荐

