Python 异步编程完整指南:async/await 实战(30 个真实案例)

Python 异步编程是 2025 年后端开发必备技能——能 5x 提升 I/O 性能。本文实战讲解 Python 异步编程 + 30 个真实案例 + 完整代码。
读完保证:能写高性能异步代码 + 处理 5x 并发 + 避免 4 大常见陷阱。

一、为什么 Python 异步编程重要?

1.1 数据

同步 vs 异步性能对比:

场景:100 个 HTTP 请求

同步:
- 总时间:100 × 200ms = 20 秒

异步:
- 总时间:200ms × 5 并发 = 1 秒

→ 5x 性能提升

1.2 真实案例

我们的 AI 服务改造:
- 同步:100 QPS
- 异步:500 QPS(5x)

→ 异步 = 后端性能核心

二、Python 异步基础

1. async/await 基础

import asyncio

async def fetch_data(url):
    """异步获取数据"""
    print(f"开始获取 {url}")
    await asyncio.sleep(2)  # 模拟 I/O
    print(f"完成 {url}")
    return f"data from {url}"

async def main():
    # 串行执行:6 秒
    data1 = await fetch_data("url1")
    data2 = await fetch_data("url2")
    data3 = await fetch_data("url3")

# 并发执行:2 秒
async def main_concurrent():
    results = await asyncio.gather(
        fetch_data("url1"),
        fetch_data("url2"),
        fetch_data("url3"),
    )

asyncio.run(main_concurrent())

2. asyncio.gather(并发执行)

import asyncio
import aiohttp

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

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

# 使用
urls = ["url1", "url2", "url3"]
results = asyncio.run(fetch_all(urls))

三、30 个真实案例

案例 1-5:HTTP 请求

# 1. 并发 HTTP 请求
async def fetch_all_pages(urls):
    async with aiohttp.ClientSession() as session:
        tasks = [session.get(url) for url in urls]
        return await asyncio.gather(*tasks)

# 2. 带超时的请求
async def fetch_with_timeout(url, timeout=5):
    async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=timeout)) as session:
        async with session.get(url) as response:
            return await response.json()

# 3. 重试机制
async def fetch_with_retry(url, max_retries=3):
    for i in range(max_retries):
        try:
            async with aiohttp.ClientSession() as session:
                async with session.get(url) as response:
                    return await response.json()
        except Exception as e:
            if i == max_retries - 1:
                raise
            await asyncio.sleep(2 ** i)  # 指数退避

# 4. 限流(信号量)
sem = asyncio.Semaphore(10)  # 最多 10 并发

async def fetch_with_limit(url):
    async with sem:
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                return await response.json()

# 5. 批量 HTTP 请求
async def batch_request(urls, batch_size=10):
    results = []
    for i in range(0, len(urls), batch_size):
        batch = urls[i:i+batch_size]
        results.extend(await fetch_all_pages(batch))
    return results

案例 6-10:数据库

# 6. asyncpg(PostgreSQL 异步)
import asyncpg

async def fetch_users():
    conn = await asyncpg.connect(
        user='user', password='pwd', database='db',
        host='localhost'
    )
    rows = await conn.fetch('SELECT * FROM users')
    await conn.close()
    return rows

# 7. 异步 ORM(SQLAlchemy 2.0)
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker

engine = create_async_engine('postgresql+asyncpg://...')
AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession)

async def get_user(user_id):
    async with AsyncSessionLocal() as session:
        result = await session.execute(
            select(User).where(User.id == user_id)
        )
        return result.scalar_one_or_none()

# 8. 异步事务
async def transfer_money(from_id, to_id, amount):
    async with AsyncSessionLocal() as session:
        async with session.begin():
            from_user = await session.get(User, from_id)
            to_user = await session.get(User, to_id)
            from_user.balance -= amount
            to_user.balance += amount

# 9. 异步批量插入
async def bulk_insert(items):
    async with engine.begin() as conn:
        await conn.execute(User.__table__.insert(), items)

# 10. 异步连接池
from asyncpg import create_pool

async def setup_pool():
    return await create_pool(
        user='user', password='pwd', database='db',
        min_size=5, max_size=20
    )

pool = asyncio.run(setup_pool())

async def query(sql):
    async with pool.acquire() as conn:
        return await conn.fetch(sql)

案例 11-15:AI / LLM 异步

# 11. 异步 LLM 调用
import openai

async def call_llm(prompt):
    client = openai.AsyncClient()
    response = await client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}]
    )
    return response.choices[0].message.content

# 12. 异步并发 LLM
async def call_many_llms(prompts):
    client = openai.AsyncClient()
    tasks = [
        client.chat.completions.create(
            model="gpt-4o",
            messages=[{"role": "user", "content": p}]
        )
        for p in prompts
    ]
    return await asyncio.gather(*tasks)

# 13. 异步 Embedding
async def embed_texts(texts):
    client = openai.AsyncClient()
    response = await client.embeddings.create(
        model="text-embedding-3-small",
        input=texts
    )
    return [d.embedding for d in response.data]

# 14. 异步 RAG
async def async_rag(query, rag_chain):
    # 异步 RAG 调用
    docs = await rag_chain.retriever.ainvoke(query)
    answer = await rag_chain.ainvoke(query)
    return answer, docs

# 15. 异步 Agent
async def async_agent(query, agent):
    result = await agent.ainvoke({"input": query})
    return result["output"]

案例 16-20:文件 I/O

# 16. 异步读文件
import aiofiles

async def read_file(path):
    async with aiofiles.open(path, 'r') as f:
        return await f.read()

# 17. 异步写文件
async def write_file(path, content):
    async with aiofiles.open(path, 'w') as f:
        await f.write(content)

# 18. 异步批量处理文件
async def process_files(paths):
    tasks = [read_file(p) for p in paths]
    contents = await asyncio.gather(*tasks)
    return contents

# 19. 异步下载文件
async def download_file(url, save_path):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            content = await response.read()
    async with aiofiles.open(save_path, 'wb') as f:
        await f.write(content)

# 20. 异步流式读取
async def stream_read(path):
    async with aiofiles.open(path, 'rb') as f:
        async for line in f:
            yield line

案例 21-25:消息队列 / 事件

# 21. 异步 Producer
import aio_pika

async def publish(message):
    connection = await aio_pika.connect_robust("amqp://...")
    channel = await connection.channel()
    await channel.default_exchange.publish(
        aio_pika.Message(message.encode()),
        routing_key="tasks"
    )
    await connection.close()

# 22. 异步 Consumer
async def consume():
    connection = await aio_pika.connect_robust("amqp://...")
    channel = await connection.channel()
    queue = await channel.declare_queue("tasks")
    async with queue.iterator() as q:
        async for msg in q:
            async with msg.process():
                await process(msg.body)

# 23. 异步任务队列(Redis)
import aioredis

async def worker():
    redis = aioredis.from_url("redis://localhost")
    while True:
        task = await redis.blpop("tasks")
        if task:
            await process_task(task[1])

# 24. 异步定时任务
async def periodic(interval, func):
    while True:
        await func()
        await asyncio.sleep(interval)

# 25. 异步回调
async def callback(event):
    await asyncio.sleep(0.1)  # 模拟处理
    print(f"处理事件: {event}")

async def main():
    events = [1, 2, 3, 4, 5]
    await asyncio.gather(*[callback(e) for e in events])

案例 26-30:实战场景

# 26. 异步 Web 爬虫
async def async_crawl(urls, max_concurrent=10):
    sem = asyncio.Semaphore(max_concurrent)

    async def fetch(url):
        async with sem:
            async with aiohttp.ClientSession() as session:
                async with session.get(url) as response:
                    return await response.text()

    return await asyncio.gather(*[fetch(u) for u in urls])

# 27. 异步任务系统
class AsyncTaskQueue:
    def __init__(self, max_workers=10):
        self.sem = asyncio.Semaphore(max_workers)
        self.results = []

    async def add_task(self, func, *args):
        async with self.sem:
            result = await func(*args)
            self.results.append(result)
            return result

    async def run(self, tasks):
        return await asyncio.gather(*[self.add_task(*t) for t in tasks])

# 28. 异步缓存
class AsyncCache:
    def __init__(self, ttl=300):
        self.cache = {}
        self.ttl = ttl

    async def get(self, key):
        if key in self.cache:
            value, ts = self.cache[key]
            if time.time() - ts < self.ttl:
                return value
        return None

    async def set(self, key, value):
        self.cache[key] = (value, time.time())

# 29. 异步限流
class AsyncRateLimiter:
    def __init__(self, max_per_second=10):
        self.sem = asyncio.Semaphore(max_per_second)

    async def acquire(self):
        await self.sem.acquire()
        # 释放(1 秒后)
        asyncio.get_event_loop().call_later(1, self.sem.release)

# 30. 异步超时控制
async def with_timeout(coro, timeout):
    try:
        return await asyncio.wait_for(coro, timeout=timeout)
    except asyncio.TimeoutError:
        return None

四、4 大常见错误

错误 1:阻塞调用

# 错
import requests
async def fetch():
    return requests.get(url)  # 阻塞!

# 对
import aiohttp
async def fetch():
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            return await resp.json()

错误 2:忘记 await

# 错
async def process():
    result = async_func()  # 忘了 await!

# 对
async def process():
    result = await async_func()

错误 3:asyncio.run() 重复

# 错
async def main():
    asyncio.run(another_async())  # 错误!嵌套 run

# 对
async def main():
    await another_async()

错误 4:CPU 密集用 async

# 错:CPU 密集任务用 async(无效)
async def compute():
    return sum(range(10_000_000))

# 对:CPU 密集用 multiprocessing
from multiprocessing import Pool
def compute():
    return sum(range(10_000_000))

五、6 个月异步学习路径

Month 1:基础
□ async/await 语法
□ asyncio.gather
□ 异步 HTTP 请求

Month 2:进阶
□ 异步数据库
□ 异步 LLM
□ 异步任务队列

Month 3:实战
□ 重构同步代码为异步
□ 性能对比
□ 监控 + 调试

Month 4-5:高级
□ 异步流
□ 异步上下文管理器
□ 异步测试

Month 6:专家
□ 完整异步架构
□ 异步 + 多线程混合
□ 性能调优

反思:异步 = 后端性能倍增器

不夸张地说:

Python 异步 = 2025 年后端性能倍增器——同步 vs 异步 = 5x 性能差距。

立即开始:今天用 async / await 重写 1 个函数 = 你的异步之旅开始。 未来 5 年,异步 = 后端工程师必会技能——必学。