Python asyncio 异步编程完全指南
目录
- 异步编程核心思想
- 同步 vs 异步 直观对比
- 网络请求对比案例
- 简化Demo(Hello→World)
- 协程基础
- 协程概念与特点
- async/await 关键字详解
- 协程函数示例(单个/多个任务)
- 事件循环(Event Loop)
- 异步IO操作
一、异步编程核心思想
异步编程是单线程中并发处理多任务的编程方式,核心优势是提升IO密集型任务(网络通信、数据库访问、文件读写)的并发性和响应性。
其核心思想是:避免阻塞——当一个任务等待IO操作(如等待网络响应、等待文件读取)时,主动让出CPU执行权,让其他任务继续执行,从而充分利用CPU时间片,避免闲置浪费。
生动类比(餐厅服务员模型)
| 模式 |
执行流程 |
核心特点 |
| 同步模式 |
接待顾客A → 记录订单 → 原地等菜 → 给A上菜 → 再接待顾客B |
等待IO时CPU闲置,效率低 |
| 异步模式 |
接待顾客A → 记录订单 → 转接待顾客B → 接待顾客C → 后厨喊菜 → 暂停C,给A上菜 → 继续接待C |
等待IO时切换任务,CPU不闲置 |
越来越多现代语言(如JavaScript、Python)支持异步编程,asyncio是Python 3.4+内置的标准库,基于事件循环和协程实现异步调度。
二、同步 vs 异步 直观对比
1. 网络请求对比案例(模拟5次延迟请求)
通过 requests(同步)和 aiohttp(异步)对比耗时,直观感受异步优势。
对比结果

关键差异:同步需依次等待每个请求完成(总耗时≈2×5=10秒),异步同时发起所有请求(总耗时≈2秒)
核心区别:Session的作用
| 库 |
Session 定位 |
核心价值 |
| requests(同步) |
同步优化工具 |
复用TCP连接(减少三次握手)、共享Cookie/Headers |
| aiohttp(异步) |
异步订单系统 |
跟踪每个异步任务的上下文,确保请求与响应一一对应 |
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import time import requests import asyncio import aiohttp
def sync_fetch(url): """同步请求单个URL(阻塞式)""" response = requests.get(url) return f"同步:请求 {url} 完成,状态码 {response.status_code}"
def sync_main(): """模拟5个同步请求""" urls = ["https://httpbin.org/delay/2" for _ in range(5)] start_time = time.perf_counter() results = [sync_fetch(url) for url in urls] end_time = time.perf_counter() for res in results: print(res) print(f"\n【同步总耗时】:{end_time - start_time:.2f} 秒\n")
async def async_fetch(session, url): """异步请求单个URL(非阻塞,让出CPU)""" async with session.get(url) as response: return f"异步:请求 {url} 完成,状态码 {response.status}"
async def async_main(): """并发执行5个异步请求""" urls = ["https://httpbin.org/delay/2" for _ in range(5)] start_time = time.perf_counter() async with aiohttp.ClientSession() as session: tasks = [async_fetch(session, url) for url in urls] results = await asyncio.gather(*tasks) end_time = time.perf_counter() for res in results: print(res) print(f"\n【异步总耗时】:{end_time - start_time:.2f} 秒")
if __name__ == "__main__": sync_main() asyncio.run(async_main())
|
2. 简化Demo(直观理解任务切换)
通过「Hello→等待1秒→World」的双任务对比,快速理解异步并发的执行逻辑。
运行效果

完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import asyncio import time
async def async_hello(): print("异步:Hello") await asyncio.sleep(1) print("异步:World")
async def async_main(): start_time = time.perf_counter() await asyncio.gather( async_hello(), async_hello() ) end_time = time.perf_counter() print(f"【异步总耗时】:{end_time - start_time:.2f} 秒\n")
def sync_hello(): print("同步:Hello") time.sleep(1) print("同步:World")
def sync_main(): start_time = time.perf_counter() sync_hello() sync_hello() end_time = time.perf_counter() print(f"【同步总耗时】:{end_time - start_time:.2f} 秒\n")
if __name__ == "__main__": print("===== 同步执行 =====") sync_main() print("===== 异步执行 =====") asyncio.run(async_main())
|
三、协程基础
1. 协程的概念和特点
协程(Coroutines)是asyncio的核心,本质是可暂停、可恢复的函数,具备以下特点:
- 单线程执行,通过「暂停/恢复」实现任务切换(无线程切换开销)
- 必须在事件循环中运行(无法直接调用协程函数)
- 暂停时会让出CPU,不阻塞其他任务执行
- 依赖
async/await 关键字实现语法支持
2. async/await 关键字详解
| 关键字 |
作用 |
核心规则 |
使用场景 |
| async |
定义协程函数/异步上下文管理器 |
只能修饰 def(协程)或 with/for(异步上下文) |
1. 定义异步函数:async def func(): ... 2. 异步上下文:async with ... |
| await |
暂停当前协程,等待可等待对象完成 |
只能在 async def 定义的协程内部使用 |
1. 等待另一个协程:await coro() 2. 等待异步IO:await asyncio.sleep() 3. 等待任务集合:await asyncio.gather() |
注:「可等待对象」包括:协程(coroutine)、任务(Task)、未来对象(Future)
3. 协程函数示例
(1)最简化的协程(单个任务)
1 2 3 4 5 6 7 8 9 10
| import asyncio
async def my_coroutine(): print("协程开始执行") await asyncio.sleep(1) return "协程执行结果"
result = asyncio.run(my_coroutine()) print("协程返回结果:", result)
|
(2)多任务聚合(统一调度多个协程)
实际开发中需调度多个协程,用 asyncio.gather() 聚合任务,统一处理结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import asyncio
async def task(name): print(f"【{name}】启动") await asyncio.sleep(1) return f"【{name}】完成"
async def main(): print("===== 主协程启动 =====") tasks = [task("任务1"), task("任务2"), task("任务3")] results = await asyncio.gather(*tasks) print("\n===== 所有任务执行完成 =====") for res in results: print(res)
if __name__ == "__main__": asyncio.run(main())
|
四、事件循环(Event Loop)
1. 核心原理
事件循环是asyncio的「调度中心」,本质是单线程的无限循环,负责:
- 管理所有协程任务的生命周期(启动、暂停、恢复、结束)
- 监听IO事件(如网络响应、文件读取完成)
- 当任务暂停时,切换到其他就绪任务
- 当IO事件完成时,唤醒等待该事件的任务
生动类比
事件循环 = 餐厅「执行总监」:
- 分配任务给服务员(协程)
- 监督任务进度(监听IO事件)
- 当服务员等待(如等菜)时,安排其去服务其他顾客(切换任务)
- 当菜做好(IO完成)时,通知服务员上菜(唤醒任务)
2. 手动配置事件循环(进阶)
Python 3.7+ 推荐用 asyncio.run() 自动管理事件循环,但也可手动配置(适合复杂场景):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import asyncio import time
async def my_coroutine(): print("协程开始执行") await asyncio.sleep(1) return "协程执行结果"
async def gather_tasks(): """聚合多个协程任务""" return await asyncio.gather( my_coroutine(), my_coroutine(), my_coroutine() )
if __name__ == "__main__": start_time = time.perf_counter()
loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) try: results = loop.run_until_complete(gather_tasks()) finally: loop.close()
end_time = time.perf_counter() print("任务结果:", results) print(f"总耗时:{end_time - start_time:.2f} 秒")
|
运行结果

五、异步IO操作
异步编程的核心价值在于优化IO密集型任务,asyncio生态提供了丰富的异步IO工具(如 aiohttp 用于网络请求,aiofiles 用于文件读写)。
1. 异步文件读写(aiofiles)
传统 open() 是阻塞式的,aiofiles 提供异步文件操作API,避免IO等待时阻塞事件循环:
1 2 3 4 5 6 7 8 9 10 11 12
| import asyncio import aiofiles
async def read_file(file_path): async with aiofiles.open(file_path, 'r', encoding='utf-8') as f: data = await f.read() print("文件内容:") print(data)
asyncio.run(read_file('flag.txt'))
|
运行结果

2. 关键注意事项
- 异步IO必须使用「异步兼容库」:如
aiohttp(替代 requests)、aiofiles(替代 open()),不能在协程中直接使用阻塞式IO库(会导致整个事件循环阻塞)
- 异步适合IO密集型任务:CPU密集型任务不适合用asyncio(单线程无法利用多核,反而不如多线程)
- 异步上下文管理器:异步操作资源时(如文件、网络连接),需用
async with 自动管理资源(类似同步的 with,但支持异步)
总结
- 核心价值:asyncio通过「协程+事件循环」实现单线程并发,解决IO密集型任务的阻塞问题,提升程序响应速度
- 关键语法:
async def 定义协程,await 暂停等待,asyncio.gather() 聚合任务
- 适用场景:网络请求、数据库操作、文件读写等IO密集型场景
- 避坑点:不混用阻塞式IO库,CPU密集型任务优先用多进程(
multiprocessing)或 concurrent.futures