Python异步编程入门:用asyncio处理高并发
Python的asyncio是处理高并发IO密集型任务的利器。相比多线程,异步编程更轻量、更可控。本文从基础概念出发,通过实例讲解asyncio的核心用法,帮助你入门异步编程。
一、为什么需要异步编程
传统的同步IO在等待网络响应、文件读写等操作时会阻塞整个线程。假设需要从100个API获取数据,每个请求耗时100ms,同步方式需要10秒以上,而异步方式可以并发发送所有请求,总耗时接近单个请求的时间。

Python的GIL(全局解释器锁)让多线程在CPU密集型任务中无法真正并行。异步编程在单线程内通过事件循环调度任务,避免了GIL的限制,特别适合IO密集型场景。
二、asyncio核心概念
### 事件循环
事件循环是异步编程的核心,它负责调度和执行协程。在Python 3.7+,可以通过asyncio.run()自动创建事件循环。
### 协程
协程是使用async def定义的特殊函数,调用时不会立即执行,而是返回一个协程对象。必须通过await或事件循环来执行。
### 任务
任务是协程的封装,用于跟踪协程的执行状态。通过asyncio.create_task()创建任务,任务可以在后台运行而不阻塞主线程。
三、基础用法
asyncio.gather()将多个协程组合成任务组,并发执行。asyncio.gather()将多个协程组合成任务组,并发执行。
asyncio.gather()将多个协程组合成任务组,并发执行。上例中3个各需1秒的任务,总耗时约1秒而非3秒。
四、实际应用场景
### 并发HTTP请求
使用aiohttp库可以发起异步HTTP请求。aiomysql、asyncpg等库支持异步数据库访问。aiofiles支持异步文件操作。
五、常见问题与解决方案
### 阻塞调用
在异步函数中使用同步阻塞调用会阻塞整个事件循环。解决方案:使用asyncio.sleep()替代time.sleep(),使用aiofiles替代open()。
### 异常处理
asyncio.gather()默认会收集所有任务的异常,不会中断执行。如果需要快速失败,使用asyncio.wait()并设置return_when参数。
### 调试技巧
异步代码的调试比同步代码困难。asyncio.run(debug=True)可以开启调试模式。
六、进阶主题
### 信号量控制并发数
使用asyncio.Semaphore限制同时执行的任务数量。
### 任务超时控制
使用asyncio.wait_for设置任务超时。
### 取消任务
使用task.cancel()取消任务。
总结
asyncio是Python处理高并发IO的现代化方案。核心是事件循环、协程和任务三要素。async/await语法让异步代码看起来像同步代码,更易维护。适合Web服务、API聚合、数据采集等IO密集型场景。
FAQ常见问题
Q:asyncio和多线程如何选择?
A:IO密集型任务优先选择asyncio,CPU密集型任务或需要真正并行的场景,选择多进程。
Q:异步函数可以调用同步函数吗?
A:可以,但同步函数必须是非阻塞的。带有time.sleep()或同步IO的函数会阻塞事件循环。
Q:asyncio的性能瓶颈在哪里?
A:单个Python进程受GIL限制,CPU密集型任务无法并行。