Python中阻塞代码为何会延迟非阻塞asyncio.sleep定时器?
问题分析:asyncio任务执行顺序异常原因
代码复现
import asyncio import time from datetime import datetime async def delay(n: int, id: str): await asyncio.sleep(n) print("I am:", id, datetime.now()) return id async def main(): second = delay(1, "second") first = delay(1, "First") task = asyncio.create_task(second) time.sleep(2) # Removable, this is here to show "second" is being delayed until after first resolves await first asyncio.run(main())
核心原因:同步阻塞卡住事件循环
asyncio的事件循环运行在单线程中,所有异步任务的调度、IO回调都依赖这个线程的执行。而time.sleep(2)是同步阻塞函数,它会直接占用整个线程,让事件循环完全停止工作,直到2秒结束。
详细时间线拆解
T+0:
- 创建
second和first协程对象(此时还没执行任何代码) - 调用
asyncio.create_task(second):事件循环启动second协程,执行到await asyncio.sleep(1),此时事件循环会把这个任务挂起,设置一个T+1的定时器,然后回到事件循环等待。 - 紧接着执行
time.sleep(2):这一步直接阻塞整个线程,事件循环被彻底卡住,无法处理任何定时器回调或任务调度。
- 创建
T+2:
time.sleep(2)结束,线程恢复,事件循环重新开始运行。- 此时执行
await first:启动first协程,执行到await asyncio.sleep(1),事件循环挂起这个任务,设置T+3的定时器。 - 现在事件循环里有两个待执行的任务:
second的定时器本应在T+1触发,但因为之前线程被阻塞,直到T+2才被事件循环发现已经超时;first的定时器在T+3触发。 - 事件循环会先处理当前
await first带来的任务调度流程,second的任务虽然超时,但需要等待事件循环进入下一次调度轮询。等到T+3时,first的sleep到期,两个任务的后续代码会被事件循环依次执行,最终几乎同时在T+3完成。
关键误区
你以为asyncio.sleep(1)在T+0就开始计时,到T+1就会自动执行后续代码,但实际上,asyncio.sleep的定时器触发后,必须等待事件循环有空才能执行后续逻辑。而time.sleep(2)直接卡住了线程,事件循环在T+0到T+2这段时间完全无法工作,根本没机会处理second的定时器回调。
验证:去掉time.sleep的效果
如果把time.sleep(2)注释掉,执行顺序就会符合预期:
- T+0:创建
second任务,执行到await asyncio.sleep(1)挂起 - 事件循环立即处理
await first,启动first协程到await asyncio.sleep(1)挂起 - T+1:两个定时器同时触发,事件循环依次执行它们的后续代码,几乎同时打印结果
内容的提问来源于stack exchange,提问作者Goblinlord
相关产品推荐
相关产品推荐

