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
相关产品推荐
相关产品推荐

