async/await 不是多线程替代品或自动加速器,仅在 i/o 阻塞时让出控制权,对 cpu 密集型任务无效;async def 定义协程对象,需 await 或 asyncio.run() 调用,且 await 仅支持 awaitable 对象。

Python 3.5+ 的 async/await 不是“多线程替代品”,也不是“自动加速器”——它只在 I/O 阻塞处让出控制权,对 CPU 密集型任务无效。
async def 定义协程,不是函数
用 async def 声明的不是普通函数,而是协程对象(coroutine object)。直接调用不会执行逻辑,只会返回一个待调度的协程:
async def fetch_data():
return "done"
<p>result = fetch_data() # ← 返回 <coroutine object fetch_data at>
print(type(result)) # <class></class></coroutine></p>
- 必须用
await在另一个协程里调用,或用asyncio.run()启动 -
return的值会被await捕获,不是返回协程本身 - 不能在普通函数里写
await,会报SyntaxError: 'await' outside async function
await 只能用于可等待对象(awaitable)
await 后面必须是实现了 __await__ 方法的对象:协程、asyncio.Future、或定义了该方法的自定义类。常见误用:
-
await time.sleep(1)→ 错!time.sleep是同步阻塞,应改用await asyncio.sleep(1) -
await requests.get(...)→ 错!requests是同步库,需换aiohttp或用loop.run_in_executor包装 -
await [1, 2, 3]→ 错!列表不是 awaitable,会报TypeError: object list can't be used in 'await' expression
asyncio.run() 是最简入口,但有隐含限制
asyncio.run() 会创建新事件循环、运行协程、关闭循环——适合脚本和测试,但不适用于已有事件循环的环境(如 Jupyter、FastAPI、Tornado):
async def main():
await asyncio.sleep(1)
print("done")
<p>asyncio.run(main()) # ✅ 正常工作</p>
- 多次调用
asyncio.run()会报RuntimeError: asyncio.run() cannot be called from a running event loop - 在已运行的异步框架中,应直接
await main(),而非再套一层run() - 它默认使用
asyncio.ProactorEventLoop(Windows)或SelectorEventLoop(Unix),一般无需手动切换
真正容易被忽略的是:协程只有在事件循环调度时才真正并发;await 不是“启动线程”,而是“挂起当前协程,交出控制权”。如果所有 await 都指向同一个慢资源(比如没做连接池的单个数据库连接),那依然会串行排队。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











