python 异步框架-编程底子与进阶:以 asyncio 为核心

[复制链接]
发表于 2025-12-1 19:55:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
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/Headersaiohttp(异步)异步订单体系跟踪每个异步使命的上下文,确保哀求与相应逐一对应完备代码
  1. import time
  2. import requests
  3. import asyncio
  4. import aiohttp
  5. # ---------------------- 同步版本 ----------------------
  6. def sync_fetch(url):
  7.     """同步请求单个URL(阻塞式)"""
  8.     response = requests.get(url)
  9.     return f"同步:请求 {url} 完成,状态码 {response.status_code}"
  10. def sync_main():
  11.     """模拟5个同步请求"""
  12.     urls = ["https://httpbin.org/delay/2" for _ in range(5)]
  13.    
  14.     start_time = time.perf_counter()
  15.     results = [sync_fetch(url) for url in urls]
  16.     end_time = time.perf_counter()
  17.    
  18.     for res in results:
  19.         print(res)
  20.     print(f"\n【同步总耗时】:{end_time - start_time:.2f} 秒\n")
  21. # ---------------------- 异步版本 ----------------------
  22. async def async_fetch(session, url):
  23.     """异步请求单个URL(非阻塞,让出CPU)"""
  24.     async with session.get(url) as response:
  25.         return f"异步:请求 {url} 完成,状态码 {response.status}"
  26. async def async_main():
  27.     """并发执行5个异步请求"""
  28.     urls = ["https://httpbin.org/delay/2" for _ in range(5)]
  29.    
  30.     start_time = time.perf_counter()
  31.     async with aiohttp.ClientSession() as session:
  32.         # 创建任务列表,并发执行
  33.         tasks = [async_fetch(session, url) for url in urls]
  34.         results = await asyncio.gather(*tasks)
  35.     end_time = time.perf_counter()
  36.    
  37.     for res in results:
  38.         print(res)
  39.     print(f"\n【异步总耗时】:{end_time - start_time:.2f} 秒")
  40. # 运行对比
  41. if __name__ == "__main__":
  42.     sync_main()
  43.     asyncio.run(async_main())
复制代码
2. 简化Demo(直观明确使命切换)

通过「Hello→等待1秒→World」的双使命对比,快速明确异步并发的实验逻辑。
运行效果


完备代码
  1. import asyncio
  2. import time
  3. # ---------------------- 异步版本 ----------------------
  4. async def async_hello():
  5.     print("异步:Hello")
  6.     await asyncio.sleep(1)  # 模拟IO等待,主动让出CPU
  7.     print("异步:World")
  8. async def async_main():
  9.     start_time = time.perf_counter()
  10.     # 并发执行两个任务
  11.     await asyncio.gather(
  12.         async_hello(),
  13.         async_hello()
  14.     )
  15.     end_time = time.perf_counter()
  16.     print(f"【异步总耗时】:{end_time - start_time:.2f} 秒\n")
  17. # ---------------------- 同步版本 ----------------------
  18. def sync_hello():
  19.     print("同步:Hello")
  20.     time.sleep(1)  # 阻塞CPU,无法切换任务
  21.     print("同步:World")
  22. def sync_main():
  23.     start_time = time.perf_counter()
  24.     sync_hello()
  25.     sync_hello()  # 串行执行,必须等前一个完成
  26.     end_time = time.perf_counter()
  27.     print(f"【同步总耗时】:{end_time - start_time:.2f} 秒\n")
  28. # 运行对比
  29. if __name__ == "__main__":
  30.     print("===== 同步执行 =====")
  31.     sync_main()
  32.    
  33.     print("===== 异步执行 =====")
  34.     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. import asyncio
  2. async def my_coroutine():
  3.     print("协程开始执行")
  4.     await asyncio.sleep(1)  # 模拟1秒IO等待
  5.     return "协程执行结果"
  6. # 启动协程(asyncio.run() 会自动创建事件循环)
  7. result = asyncio.run(my_coroutine())
  8. print("协程返回结果:", result)
复制代码
(2)多使命聚合(同一调理多个协程)

实际开辟中需调理多个协程,用 asyncio.gather() 聚合使命,同一处理处罚效果:
  1. import asyncio
  2. async def task(name):
  3.     print(f"【{name}】启动")
  4.     await asyncio.sleep(1)  # 模拟IO等待
  5.     return f"【{name}】完成"
  6. async def main():
  7.     print("===== 主协程启动 =====")
  8.     # 创建3个并发任务
  9.     tasks = [task("任务1"), task("任务2"), task("任务3")]
  10.     # 等待所有任务完成,收集结果
  11.     results = await asyncio.gather(*tasks)
  12.    
  13.     print("\n===== 所有任务执行完成 =====")
  14.     for res in results:
  15.         print(res)
  16. if __name__ == "__main__":
  17.     asyncio.run(main())
复制代码
四、变乱循环(Event Loop)

1. 核心原理

变乱循环是asyncio的「调理中心」,本质是单线程的无穷循环,负责:

  • 管理全部协程使命的生命周期(启动、停息、规复、竣事)
  • 监听IO变乱(如网络相应、文件读取完成)
  • 当使命停息时,切换到其他停当使命
  • 当IO变乱完成时,叫醒等待该变乱的使命
生动类比

变乱循环 = 餐厅「实验总监」:

  • 分配使命给服务员(协程)
  • 监视使命进度(监听IO变乱)
  • 当服务员等待(如等菜)时,安排其去服务其他顾客(切换使命)
  • 当菜做好(IO完成)时,关照服务员上菜(叫醒使命)
2. 手动设置变乱循环(进阶)

Python 3.7+ 保举用 asyncio.run() 自动管理变乱循环,但也可手动设置(恰当复杂场景):
  1. import asyncio
  2. import time
  3. async def my_coroutine():
  4.     print("协程开始执行")
  5.     await asyncio.sleep(1)
  6.     return "协程执行结果"
  7. async def gather_tasks():
  8.     """聚合多个协程任务"""
  9.     return await asyncio.gather(
  10.         my_coroutine(),
  11.         my_coroutine(),
  12.         my_coroutine()
  13.     )
  14. if __name__ == "__main__":
  15.     start_time = time.perf_counter()
  16.     # 手动创建并绑定事件循环
  17.     loop = asyncio.new_event_loop()
  18.     asyncio.set_event_loop(loop)
  19.    
  20.     try:
  21.         # 运行直到任务完成
  22.         results = loop.run_until_complete(gather_tasks())
  23.     finally:
  24.         # 关闭事件循环(释放资源)
  25.         loop.close()
  26.     end_time = time.perf_counter()
  27.     print("任务结果:", results)
  28.     print(f"总耗时:{end_time - start_time:.2f} 秒")
复制代码
运行效果


五、异步IO操纵

异步编程的核心代价在于优化IO麋集型使命,asyncio生态提供了丰富的异步IO工具(如 aiohttp 用于网络哀求,aiofiles 用于文件读写)。
1. 异步文件读写(aiofiles)

传统 open() 是壅闭式的,aiofiles 提供异步文件操纵API,克制IO等待时壅闭变乱循环:
  1. import asyncio
  2. import aiofiles
  3. async def read_file(file_path):
  4.     # 异步打开文件(async with 是异步上下文管理器)
  5.     async with aiofiles.open(file_path, 'r', encoding='utf-8') as f:
  6.         data = await f.read()  # 异步读取,不阻塞事件循环
  7.         print("文件内容:")
  8.         print(data)
  9. # 启动异步文件读取
  10. 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
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表