第一次用 asyncio 十有八九会写成这样,然后发现耗时和不写异步一模一样:
import asyncio, time
async def fetch(x):
time.sleep(1) # ← 问题在这
return x * 2
async def main():
return await asyncio.gather(*[fetch(i) for i in range(5)])
asyncio.run(main()) # 耗时 5 秒,不是 1 秒
原因
time.sleep() 是阻塞调用,它会把整个线程(也就是整个事件循环)卡住。asyncio 是单线程协程,靠的是「遇到 IO 就让出控制权」来实现并发,你在协程里放一个阻塞函数,让都让不出去,自然退化成串行。
正确写法
把阻塞调用换成对应的异步版本:
async def fetch(x):
await asyncio.sleep(1) # 异步版
return x * 2
网络请求同理:requests 是阻塞的,要用 aiohttp / httpx.AsyncClient。
真没异步库怎么办
比如要调用一个只有同步接口的 SDK,丢到线程池里跑:
result = await asyncio.to_thread(blocking_func, arg) # Python 3.9+
第二个坑:忘了 await
async def main():
fetch(1) # 只是创建了协程对象,根本没执行
这种不会报错,日志里一片安静,是最难查的一类。开个 lint 规则或者直接用 asyncio.gather 包起来就好很多。
一句话总结:
async只是声明,并发靠的是不阻塞 + await 让出。
楼主 · 2026-09-28 13:21 · 浏览 22

