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

为何Python中await long_function无法实现协程异步执行?附示例

为什么await long_function()无法触发协程切换?

要搞懂这个问题,得从Python asyncio的协作式多任务核心逻辑说起:

1. 协程切换的前提:主动让出控制权

asyncio的事件循环是协作式的,和操作系统的抢占式多线程不同——协程不会被强制打断,必须自己主动“举手”告诉事件循环:“我现在可以暂停,你去跑别的协程吧”。

只有当await的对象是一个能触发事件循环调度的可等待对象时,才会发生协程切换。这类对象包括:

  • asyncio.Task/asyncio.Future:代表异步任务
  • 内置的异步IO操作(比如asyncio.sleep()、异步网络请求)
  • 自定义的实现了__await__方法且主动让出控制权的对象

2. 你的long_function只是个“伪异步”函数

你写的long_function虽然用async定义,但里面是纯CPU密集的同步循环:

async def long_function():
    for _ in range(50000000):
        pass

它没有任何IO操作,也没有调用任何会让事件循环接管的API。当你await long_function()时,事件循环会执行这个函数的所有代码——因为这个函数没有任何“暂停点”,它会一直占用单线程,直到把5000万次循环跑完,才会回到事件循环,这时才会切换到另一个count协程。

这就是为什么你看到的是第一个count打印完0-9,才轮到第二个count执行。

3. asyncio.sleep(0)的作用:主动触发调度

asyncio.sleep(0)虽然不会让程序等待实际时间,但它是asyncio提供的标准可等待对象。当你await它时,它会主动向事件循环发出信号:“我暂时不需要执行,你去调度其他就绪的协程吧”。

这时事件循环会把当前count协程挂起,转而运行另一个等待执行的count协程,于是就出现了你预期的交替输出:0、0、1、1...

总结

  • 不是所有await都会触发协程切换,只有当await的对象主动让出控制权时才会发生。
  • 纯CPU密集的async函数不会触发切换,因为它没有给事件循环调度的机会。
  • asyncio.sleep(0)是一种手动触发协程切换的技巧,适用于需要在CPU密集型代码中主动让出控制权的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 23:08:20