(七)协程对象与 await
1. 调用异步函数还没有执行函数体
async def 定义异步函数,调用后得到协程对象。先看它何时真正开始:
# 项目文件:demos/coroutine_start.py
# 先建立协程对象,再用 await 推进它;sleep(0) 让出一次执行机会。
import asyncio
async def read_title(trace):
trace.append("进入函数")
await asyncio.sleep(0)
trace.append("等待后恢复")
return "Python"
async def main():
trace = []
operation = read_title(trace)
print(type(operation).__name__, trace)
title = await operation
print(title, trace)
if __name__ == "__main__":
asyncio.run(main())先输出 coroutine [],再输出 Python ['进入函数', '等待后恢复']。普通函数调用时立刻进入函数体,协程调用先交回一个等待执行的对象;这里的 await 才继续推进它。
asyncio.run(main()) 为脚本建立并管理事件循环,运行入口协程,退出时收尾。已经运行事件循环的交互环境可以直接 await main(),不再在其中嵌套一次 run。
2. 等待的对象与当前任务
await 接收可等待对象,例如协程、Task 与异步库交回的等待结果。它会取得这个操作的结果,也会传播操作中的异常。遇到尚未完成的异步等待时,当前任务可以暂停,循环转而推进其他准备好的工作。
一个异步函数可以在没有等待的情况下直接返回;await 这样的函数不一定暂停。把耗时循环包成 async def,再写一次 await,也不会自动把这段计算变成后台并行工作。