You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 02:42:08