await 不是无条件让出控制权的魔法,而是调用右值的__await__方法获取迭代器并推进;若对象已就绪则立即返回,否则交还事件循环;仅限async函数内使用,语法编译时报错。

await 不是“让出控制权”的魔法
它只是告诉 Python:当前协程必须暂停,直到右边的 awaitable 对象(比如 async def 函数返回的 coroutine、Task、Future)完成;暂停后控制权交还事件循环,但**不是无条件让出**——如果右边对象已经就绪(例如刚创建的已完成 Future),await 会立刻返回结果,不切换上下文。
常见误解是“await 一定会 yield”,其实它底层调用的是对象的 __await__() 方法,本质是迭代一个生成器(返回 iterator),而事件循环只在迭代中途遇到 yield 才真正挂起。
await 只能在 async 函数里用,且不能嵌套在普通函数中
这是语法硬限制,不是运行时检查。Python 解释器在编译阶段就报错:SyntaxError: 'await' outside async function。
容易踩的坑:
立即学习“Python免费学习笔记(深入)”;
- 在同步工具函数(如
logging.debug()或print())里试图await异步结果——必须把整个调用链升为async - 误以为
threading.Thread或multiprocessing.Process内能直接用await——它们运行在独立线程/进程,没有事件循环上下文 - 在
__init__中写await——构造函数不能是async,需改用工厂函数(如async def create_instance(): ...)
await 的实际开销:一次属性查找 + 一次迭代器推进
每次 await 表达式执行,Python 会:
万通CMS网站管理系统采用PHP+MYSQL技术,支持伪静态功能,可生成google和百度地图,支持自定义url、关键字和描述,利于SEO搜索。拥有企业网站常用的模块功能(企业简介功能、新闻功能、产品功能、下载功能、图片功能、案例功能、在线留言、在线订单、友情链接、网站地图等等),功能强大,操作简单,灵活实用,是企业建站的神兵利器。我们的愿望是:让每个人都能用上 好用,实用,美观的网站,因为建站如
- 检查右值是否实现了
__await__(或继承自Awaitable) - 调用它拿到迭代器
- 对迭代器调用
send(None),直到它yield或抛出StopIteration
这意味着:
- 对已结束的
coroutine或Future,await是纯同步操作,耗时纳秒级 - 对真正需要挂起的(如
await asyncio.sleep(1)),开销主要在事件循环调度,而非await本身 -
await不等价于yield from:后者可委托任意迭代器,await只接受明确标记为awaitable的对象
别拿 await 当同步代码的“装饰”来用
比如写 await some_sync_function() 是非法的,因为同步函数不返回 awaitable;强行包装成 await asyncio.to_thread(some_sync_function) 也不是“让同步变快”,只是把它丢进线程池避免阻塞事件循环。
更隐蔽的问题:
- 在 CPU 密集型逻辑里滥用
await asyncio.sleep(0)企图“让出时间片”——这不会提升吞吐,反而增加调度负担 - 用
await包裹未await的协程(如await my_async_func而非await my_async_func())——会触发RuntimeWarning: coroutine 'xxx' was never awaited,且该协程根本不会执行
真正决定异步行为的,是对象是否实现了 __await__,以及事件循环是否在运行;await 只是那个“触发点”,不是开关,也不是胶水。









