async函数调用不执行而返回coroutine对象,必须用await(在async函数内)或asyncio.run()(在顶层)驱动;await只能在async函数中使用,asyncio.run()仅用于最外层入口。

async 函数不能直接调用,会返回 coroutine 对象
你写了个 async def fetch_data(),然后直接写 fetch_data() —— 这不会执行函数体,只会得到一个 <coroutine object fetch_data at></coroutine>。这是最常被忽略的起点错误。
根本原因:Python 的 async 函数是协程函数,调用它只是创建协程对象,不触发执行。必须用 await(在另一个 async 函数里)或 asyncio.run()(在顶层)来驱动。
- 在
async函数内调用:用await fetch_data() - 在普通函数或模块顶层调用:用
asyncio.run(fetch_data()) - 误用
fetch_data()后又传给print()或json.dumps(),会看到 coroutine 对象字符串,不是你想要的数据 -
asyncio.run()每次调用都会新建事件循环,不能在已运行的 loop 中重复调用(比如 Jupyter、FastAPI 生命周期里)
await 只能在 async 函数里用,否则 SyntaxError
写 await fetch_data() 却没把它包在 async def 里?Python 直接报错:SyntaxError: 'await' outside async function。这不是运行时错,是解析期就拦下来的。
常见场景包括:交互式终端(IPython)、脚本顶层、类方法没加 async、或者想在 __init__ 里 await —— 全都不行。
立即学习“Python免费学习笔记(深入)”;
Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。它虽然不是Linux系统核心的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。因此,对于用户来说,shell是最重要的实用程序,深入了解和熟练掌握shell的特性极其使用方法,是用好Linux系统
- IPython/Jupyter 中可用
await fetch_data()(因为它们底层做了魔法处理),但纯 Python 脚本不行 - 类方法要 await,必须声明为
async def method(self),且调用处也要await obj.method() -
__init__不能是async,想初始化异步资源得用工厂函数(如async def create_client(): return Client(await connect()))
asyncio.run() 是入口,不是万能胶水
asyncio.run() 看起来方便,但它只该用在程序最外层,比如脚本入口。滥用会导致事件循环冲突、资源未清理、甚至死锁。
典型误用:在 Web 框架(如 Flask、Django)视图里调用 asyncio.run();或在 for 循环里反复调用它去发多个请求 —— 每次都启停 loop,开销大且不可靠。
- Web 框架需匹配异步生命周期:FastAPI/Starlette 原生支持
async def路由;Flask 则需插件或改用 Quart - 并发请求别写
[asyncio.run(fetch(i)) for i in range(10)],应改用await asyncio.gather(*[fetch(i) for i in range(10)]) -
asyncio.run()会自动关闭 loop,若你手动调了asyncio.get_event_loop(),再调它会报RuntimeError: asyncio.run() cannot be called from a running event loop
await 表达式本身不“等待”,它让出控制权
await 不是“阻塞等结果”,而是告诉解释器:“我现在卡住了,你先去跑别的协程,等这东西 ready 了再叫我”。理解这点,才能避开“为什么加了 await 还慢”这类困惑。
性能关键点在于:await 的对象是否真能并发(比如 asyncio.sleep()、aiohttp.ClientSession.get()),还是只是个包装了同步调用的假协程(比如忘了把 requests.get() 换成 aiohttp)。
- await 一个 CPU 密集型任务(如
await asyncio.to_thread(math.factorial, 100000))才合理;直接 awaittime.sleep()会阻塞整个 event loop - 第三方库是否真异步?查文档看它返回的是
coroutine还是普通值;requests全是同步的,aiohttp/httpx.AsyncClient才是真异步 - await 链过长(如
await f1(); await f2(); await f3())默认是串行,想并发得显式用gather或create_task
async 的语义边界很清晰:它不改变单次调用的逻辑,只改变调度方式。最容易被绕晕的地方,是把“写了 async”当成“自动变快”——其实只是给了你组织并发的工具,怎么用,还得自己画清依赖和等待点。









