一、await 的核心作用

await 的作用是:暂停当前协程的执行,将控制权交还给事件循环(event loop),直到等待的对象“完成”后再恢复执行,并获取其结果。

类比理解:

想象你在排队买咖啡:

  • step1. 你点单后(发起 I/O 请求),店员说“稍等,正在做”
  • step2. 你不会傻站着(阻塞),而是去刷手机(事件循环执行其他任务)
  • step3. 咖啡好了(I/O 完成),店员叫你(事件循环唤醒你)
  • step4. 你拿到咖啡(获取结果),继续走路

await 就是那个“点单(step1) + 等待叫号(step3)”的动作。


二、await 后面能接什么?——必须是 “awaitable” 对象

await 不能接任意对象,只能接实现了 __await__ 方法的对象,即 “awaitable”

Python 中主要有三类 awaitable 对象:

类型说明示例
1. 协程(Coroutine)由 async def 定义的函数调用返回fetch_data()
2. Task对协程的封装,由事件循环调度asyncio.create_task(fetch_data())
3. Future底层异步操作的占位符(通常由库内部使用)loop.run_in_executor(...) 返回

✅ 重点

  • async def func(): ... 定义的是协程函数
  • 调用 func() 返回的是协程对象(coroutine object)
  • 这个协程对象就是 awaitable 的!

三、详细示例解析

示例 1:await 协程对象(最常见)

import asyncio

async def fetch_data():
    await asyncio.sleep(1)  # 模拟异步 I/O
    return "Data from server"

async def main():
    # fetch_data() 返回一个协程对象
    coro = fetch_data()
    print(type(coro))  # <class 'coroutine'>
    
    # await 它,会执行并返回结果
    result = await coro
    print(result)  # "Data from server"

asyncio.run(main())

✅ 过程

  1. fetch_data() 创建协程对象(未执行!)
  2. await coro → 事件循环开始执行该协程
  3. 遇到 await asyncio.sleep(1) → 暂停,让出控制权
  4. 1 秒后,sleep 完成 → 恢复执行 → 返回 "Data from server"
  5. result 得到该值

示例 2:await Task(推荐用于并发)

async def main():
    # 创建 Task(立即被调度)
    task = asyncio.create_task(fetch_data())
    
    # 可以做其他事...
    print("Doing other work...")
    
    # 等待 Task 完成并获取结果
    result = await task
    print(result)

💡 Task vs 协程对象

  • 直接 await fetch_data():顺序执行
  • task = create_task(...); await task:可与其他任务并发(虽然这里只等一个)

示例 3:await 多个任务(并发)

async def main():
    # 同时启动多个任务
    task1 = asyncio.create_task(fetch_data())
    task2 = asyncio.create_task(fetch_data())
    
    # 等待全部完成
    r1 = await task1
    r2 = await task2
    # 或
    r1, r2 = await asyncio.gather(task1, task2)

四、await 如何返回结果?

✅ 规则很简单:

await some_awaitable 的值 = 该 awaitable 最终 return 的值

async def add(a, b):
    return a + b  # ← 返回值

async def main():
    result = await add(2, 3)  # result = 5

❌ 如果协程抛出异常:

async def bad():
    raise ValueError("Oops!")

async def main():
    try:
        await bad()
    except ValueError as e:
        print(e)  # "Oops!" —— 异常会被 re-raise

⚠️ 重要await 不仅传递结果,也传递异常!


五、常见误区澄清

❌ 误区 1:await 只能接 async def 函数调用

✅ 正确:可以接任何 awaitable(Task、Future、自定义 awaitable)

❌ 误区 2:await func() 会“启动”函数

✅ 正确:func() 已经创建了协程对象,await 是“执行并等待完成”

❌ 误区 3:await 是“阻塞”的

✅ 正确:对当前协程是“暂停”,但对整个程序是非阻塞的
事件循环会去执行其他协程。


六、自定义 awaitable 对象(高级)

你也可以让自己的类支持 await

class MyAwaitable:
    def __await__(self):
        # 必须返回一个 generator 或 awaitable
        yield from asyncio.sleep(1).__await__()
        return "Custom result"

async def main():
    result = await MyAwaitable()
    print(result)  # "Custom result"

💡 实际开发中极少需要,但理解这点有助于掌握原理。


七、总结:await 的本质

问题答案
await 的作用?暂停当前协程,交出控制权,等待异步操作完成
后面接什么?必须是 awaitable 对象(协程、Task、Future)
如何返回结果?返回该 awaitable 的 return 值(或抛出异常)
是否阻塞?不阻塞事件循环,只暂停当前协程
必须在 async def 中使用?✅ 是的!否则语法错误

💡 终极口诀
await 等的是‘未来’,拿的是‘结果’,放的是‘控制权’。”

掌握这一点,你就真正理解了 Python 异步编程的精髓!

更多推荐