2026-02-28

asyncio 爬坑记录

python async

Python 的 asyncio 折腾了两天,总算把事件循环、协程、async/await 这些概念理清楚了。记录一下学习和踩坑的过程。

为什么需要 asyncio

IO 密集型任务(网络请求、文件读写)等待的时候 CPU 是空闲的。异步编程让 CPU 在等待的时候去处理其他任务,提高效率。

核心概念

事件循环(Event Loop):程序的指挥中心,负责调度所有任务。

协程(Coroutine):可以被暂停和恢复的函数,用 async def 定义。

Future:代表还未完成的任务结果。

基本用法

import asyncio

async def hello():
    print('Hello')
    await asyncio.sleep(1)  # 模拟 IO 操作
    print('World')

# 运行
asyncio.run(hello())

await 的坑

最大的坑:忘了 await

# 错误写法:函数不会执行
result = asyncio.sleep(1)  # 这只是个协程对象,没执行

# 正确写法
await asyncio.sleep(1)  # 加 await 才会真正执行

我之前就是忘了加 await,导致代码完全不按预期运行。

gather vs wait

并发执行多个任务:

# gather:等待所有任务完成,返回结果列表
results = await asyncio.gather(task1(), task2(), task3())

# wait:可以设置条件,返回完成的、未完成的
done, pending = await asyncio.wait(
    [task1(), task2(), task3()],
    return_when=asyncio.FIRST_COMPLETED  # 第一个完成就返回
)

用 gather 更简单,wait 更灵活。

实际应用

并发请求多个 API:

async def fetch_all(urls):
    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, url) for url in urls]
        return await asyncio.gather(*tasks)

async def fetch(session, url):
    async with session.get(url) as resp:
        return await resp.json()

常见错误

总结

asyncio 适合 IO 密集型任务,不适合 CPU 密集型任务(用 multiprocessing)。

理解事件循环的工作原理很重要,不然会踩很多坑。