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

Python Asyncio/Await循环中await的阻塞机制疑问

Asyncio中await阻塞机制的疑问解答

你之前对await的理解有个关键偏差:await不是只把协程丢进事件循环排队就完事,它会直接暂停当前协程的执行,把控制权交还给事件循环,直到被await的对象(协程、Future、Task)执行完成并返回结果,当前协程才会继续往下走。

为什么Code Block A里的await没阻塞后续打印?

你看到的“未阻塞”,本质是被await的协程瞬间就执行完了。比如Code Block A可能是这样的:

import asyncio

async def fast_task():
    # 没有IO等待、没有耗时操作,直接返回结果
    return "done"

async def main():
    print("执行await前")
    await fast_task()
    print("执行await后")

asyncio.run(main())

这里await fast_task()确实会暂停main协程,但因为fast_task没有任何等待步骤,立刻就完成了,main协程几乎瞬间恢复,所以后续的print看起来像是没被阻塞。

如果是另一种场景:你把后续打印放进了另一个独立协程并提交给事件循环,那事件循环会在当前协程暂停时调度那个打印协程,这也会让你产生“await没阻塞打印”的错觉,但本质是两个协程在事件循环里交替执行,不是await没起作用。

为什么Code Block B里每次循环迭代会有类似threading.join()的阻塞效果?

Code Block B里用aiohttp发起API请求,这是典型的IO密集型操作——当你await fetch_stock_data(...)时,这个协程会发起网络请求,然后进入等待服务器响应的状态。这时候:

  1. 当前协程(也就是main函数里的循环逻辑)会被暂停,把控制权交还给事件循环;
  2. 事件循环会等待这个IO操作完成(等待期间如果有其他已就绪的协程,事件循环会去执行它们,但你的例子里没有额外任务);
  3. 当API响应返回后,被await的协程完成,main协程才会恢复,继续执行下一次循环迭代。

这种“每次循环必须等上一次请求完成才会继续”的效果,看起来就像threading里的join()——但要注意,这不是阻塞整个线程,只是阻塞当前协程的执行流程。如果在循环的同时,你给事件循环提交了其他任务(比如一个定时打印的协程),事件循环会在等待API响应的间隙去执行那个任务,线程并不会被完全卡住。

Code Block B的典型代码大概是这样的:

import asyncio
import aiohttp

async def fetch_stock(session, symbol):
    url = f"https://api.example.com/stock/{symbol}"
    async with session.get(url) as resp:
        return await resp.json()

async def main():
    symbols = ["AAPL", "GOOG", "MSFT"]
    async with aiohttp.ClientSession() as session:
        for sym in symbols:
            # 每次迭代都await,必须等当前请求完成才会进入下一次循环
            data = await fetch_stock(session, sym)
            print(f"获取到{sym}的数据:{data}")

asyncio.run(main())

这里的循环会严格按顺序执行,每次都要等前一个API请求完成,才会处理下一个股票代码,这就是你看到的“类似join()的阻塞效果”——本质是await的固有机制:暂停当前协程,等待目标可等待对象完成后再继续。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 00:30:55