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

Python并发非阻塞机制疑惑:asyncio.sleep与gather执行差异问询

关于Python asyncio中sleep与并发的疑惑解答

核心区别:任务的启动时机

  • Case A(顺序await):你是先启动第一个sleep,等它完全结束后,才启动第二个sleep。
    当执行await asyncio.sleep(5)时,当前协程确实会把控制权交还给事件循环,但此时事件循环里没有其他待执行任务,只能等这个sleep的5秒结束。等第一个sleep完成,代码才会走到下一行的await asyncio.sleep(5),这时候第二个sleep才被提交到事件循环,再等5秒,总耗时自然是10秒。不是第一个任务阻塞了程序,而是第二个任务根本还没被启动,事件循环没的选,只能等第一个完成。

  • Case B(asyncio.gather):asyncio.gather会同时把所有传入的协程包装成任务,提交到事件循环。
    两个sleep任务几乎同时被启动,当第一个sleep暂停并交还控制权时,事件循环发现还有第二个sleep任务在等待执行,就会切换到第二个任务。两个sleep是并行等待的,所以5秒后两个任务都完成,总耗时5秒。

关键概念再梳理

  • asyncio.sleep本身是非阻塞的:它不会占用CPU,只是告诉事件循环“我要暂停X秒,这段时间你去干别的”。但前提是,事件循环里得有别的任务可干。
  • 协作式并发的核心:协程要交还控制权,但也要有其他任务已经被提交到事件循环,调度器才有东西可切换。顺序await的情况下,第二个任务还没被创建,调度器自然没法切换过去。

直观代码示例

# Case A 顺序执行代码
import asyncio

async def main():
    print("Start task 1")
    await asyncio.sleep(5)  # 事件循环仅这一个任务,等待5秒
    print("Finish task 1")
    print("Start task 2")
    await asyncio.sleep(5)  # 此时才启动第二个任务,再等5秒
    print("Finish task 2")

asyncio.run(main())
# 输出顺序:Start task1 → 等待5秒 → Finish task1 → Start task2 → 等待5秒 → Finish task2
# 总耗时10秒
# Case B 并发执行代码
import asyncio

async def main():
    task1 = asyncio.create_task(asyncio.sleep(5))
    task2 = asyncio.create_task(asyncio.sleep(5))
    print("Both tasks started")
    await asyncio.gather(task1, task2)
    print("Both tasks finished")

asyncio.run(main())
# 输出顺序:Both tasks started → 等待5秒 → Both tasks finished
# 总耗时5秒

这里用create_task显式创建任务,和gather的效果本质一致:都是提前把多个任务提交到事件循环,让调度器能在一个任务暂停时切换到另一个。

内容的提问来源于stack exchange,提问作者nisixo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 20:56:04