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

使用time.sleep自定义my_sleep,asyncio.gather为何未实现预期并发?

为什么asyncio.gather无法像线程那样处理time.sleep的IO操作?

我尝试自定义协程函数my_sleep,内部调用time.sleep而非asyncio.sleep(),用asyncio.gather执行my_sleep(4)和my_sleep(7)时,预期总耗时7秒,但实际用了约11秒;而用线程实现类似逻辑时,总耗时符合预期的7秒。请问asyncio.gather创建的Task对象为何无法像线程那样将time.sleep识别为IO绑定操作?

代码示例:

import time
import asyncio


async def my_sleep(delay):
    time.sleep(delay)

async def main():
    start = time.time()
    await asyncio.gather(my_sleep(4), my_sleep(7))
    print("Took", time.time()-start, "seconds")

asyncio.run(main())

# Expected: Took 7 seconds
# Got: Took 11.011508464813232 seconds

原因解释

  1. asyncio是单线程协作式调度模型
    asyncio的事件循环运行在单个线程中,所有Task的切换完全依赖于当前Task主动让出CPU控制权。只有当Task执行到await一个可等待对象(比如asyncio.sleep、异步IO操作)时,才会把控制权交还给事件循环,让其他Task有机会运行。

  2. time.sleep是同步阻塞调用,会卡住整个线程
    time.sleep(delay)是一个同步阻塞函数,它会让整个线程进入休眠状态,期间事件循环完全无法调度其他Task。你的my_sleep协程调用time.sleep时,事件循环线程被死死卡住,必须等这个sleep执行完,才会去处理另一个my_sleep任务,所以总耗时是4+7=11秒。

  3. asyncio.sleep才是异步友好的休眠方式
    asyncio.sleep(delay)是专门为异步框架设计的可等待对象,当你await它时,当前Task会主动把控制权交还给事件循环,事件循环可以立刻调度其他就绪的Task。这样两个休眠任务就能“并行”执行,总耗时取两个延迟的最大值7秒。

  4. 线程是抢占式调度模型
    线程由操作系统负责调度,采用抢占式策略:当一个线程调用time.sleep进入休眠时,操作系统会主动把CPU时间片分配给其他线程,所以两个线程的sleep操作是真正并行的,总耗时自然是较长的那个7秒。


内容的提问来源于stack exchange,提问作者AK-CHP

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 15:27:48