async def函数中混用同步调用会阻塞事件循环,必须自底向上将所有I/O操作(如HTTP、DB、文件)替换为异步实现,否则导致“假异步”,并发失效。

不是“必须遵守”,而是不遵守就大概率写出不可靠、难调试、甚至阻塞整个事件循环的代码。
async def 函数里混同步调用会直接卡死事件循环
事件循环是单线程调度器,一旦某个协程里执行了 time.sleep(1)、requests.get() 或任何未异步封装的 I/O 操作,它就会阻塞整个 loop——其他所有协程都得等它结束。这不是“慢”,是“全停”。
-
time.sleep()必须换成await asyncio.sleep() -
requests.get()必须换成aiohttp.ClientSession().get()或httpx.AsyncClient().get() - 数据库操作必须用
aiomysql、asyncpg、motor等异步驱动,不能用pymysql或sqlite3
同步逻辑向上渗透会导致“假异步”陷阱
常见错误是只把最外层函数改成 async def main(),但里面层层调用的仍是同步函数。结果表面用了 asyncio.run(),实际还是串行执行,耗时和同步版本几乎一样。
- 从最底层 I/O 操作(HTTP 请求、文件读写、DB 查询)开始异步化,而不是从入口函数开始
- 每个依赖项都要检查是否原生支持 async —— 比如
json.loads()是同步 CPU 操作,没问题;但open()默认是同步的,得用await aiofiles.open() - 第三方库没提供异步接口?别硬包一层
loop.run_in_executor()就算完事——这只能缓解 CPU 密集型阻塞,对 I/O 无效,还增加线程调度开销
自底向上不是风格选择,是调度机制决定的硬约束
Python 的 asyncio 不是“多线程模拟”,它的并发本质是协作式调度:每个协程必须主动让出控制权(通过 await),事件循环才能切到下一个任务。这个让出点,必须落在真正可暂停的位置(即异步 I/O 调用),而不是你随便加个 await asyncio.sleep(0)。
立即学习“Python免费学习笔记(深入)”;
-
await后面的对象必须是Awaitable(有__await__方法),普通函数返回值不是 - 同步函数返回值无法
await,强行await sync_func()会报TypeError: object xxx can't be used in 'await' expression - 哪怕只有一处漏掉异步化,整条调用链就断在那儿,上层再怎么
gather也并发不起来
真正的难点不在写 async/await 语法,而在于识别哪些调用是“真 I/O”、哪些只是“看起来像”,以及能否拿到对应异步实现——这才是自底向上不可绕开的实质。



















