异步编程基础

Python的异步编程通过asyncio库实现,核心概念包括协程、事件循环和Future。理解这些概念是掌握异步编程的前提。

协程与事件循环

协程的定义

协程是使用async def定义的函数,调用时返回一个协程对象:

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

协程只有在事件循环中执行才会真正运行。

事件循环

事件循环是异步编程的核心调度器,负责管理所有待执行的协程:

async def main():
    result = await fetch_data("https://api.example.com/data")

# Python 3.7+ 自动创建事件循环
asyncio.run(main())

并发执行模式

使用asyncio.gather

并发执行多个协程并等待所有完成:

async def main():
    results = await asyncio.gather(
        fetch_data("https://api1.com"),
        fetch_data("https://api2.com"),
        fetch_data("https://api3.com"),
        return_exceptions=True  # 不因单个异常中断
    )

使用asyncio.create_task

创建后台任务,适用于不需要立即等待的场景:

async def main():
    task1 = asyncio.create_task(fetch_data("url1"))
    task2 = asyncio.create_task(fetch_data("url2"))
    # 执行其他操作
    await asyncio.sleep(1)
    # 等待任务完成
    result1 = await task1
    result2 = await task2

高级模式

异步上下文管理器

使用async with管理异步资源:

class AsyncDB:
    async def __aenter__(self):
        self.conn = await create_connection()
        return self.conn

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.conn.close()

异步迭代器

使用async for处理异步数据流:

async def read_stream():
    async for chunk in stream_reader:
        process(chunk)

限制并发数

使用asyncio.Semaphore控制并发度:

sem = asyncio.Semaphore(10)

async def limited_fetch(url):
    async with sem:
        return await fetch_data(url)

常见陷阱与最佳实践

避免阻塞事件循环

在协程中使用同步阻塞调用会阻塞整个事件循环。

错误示例:

async def bad():
    time.sleep(1)  # 阻塞整个事件循环!

正确做法:

async def good():
    await asyncio.sleep(1)  # 非阻塞
    # 或使用线程池执行阻塞操作
    result = await asyncio.to_thread(sync_function)

线程安全

大部分asyncio对象不是线程安全的,跨线程调用需要使用loop.call_soon_threadsafe

调试异步代码

  • 启用PYTHONASYNCIODEBUG=1环境变量
  • 使用asyncio.run(main(), debug=True)
  • 设置loop.slow_callback_duration检测慢回调

异步编程能显著提升IO密集型应用的性能,但需要理解其底层机制才能编写出正确高效的代码。