• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
28.7的博客
等小白学会了游泳,我们天天海边,学会了滑板,我们夏天去冲浪冬天去滑雪,只要你愿意,我们去经历各种各样有趣的事情~ “鸡毛!我学会了发现冰激凌烧烤奶茶火锅,我们天天去吃!现在就去!” “●﹏●;”
博客园    首页    新随笔    联系   管理    订阅  订阅
python 异步框架-编程基础与进阶:以 asyncio 为核心
python 异步框架-编程基础与进阶:以 asyncio 为核心 该文章围绕 Python asyncio 异步编程展开全面讲解,先以生动的餐厅服务员类比阐释异步编程 “避免阻塞、提升 CPU 利用率” 的核心思想,对比同步与异步模式的执行差异。随后通过网络请求和简化的 Hello - World 两个实战案例,直观展现了 requests 同步库与 aiohttp 异步库的耗时差距,点明两者 Session 的不同定位。文章还详解了 async/await 关键字的用法、协程的定义与多任务聚合方式,深入剖析事件循环的调度原理并给出手动配置示例,最后介绍了基于 aiofiles 的异步 IO 操作,整体内容从基础概念到实战代码,逻辑清晰,兼顾原理讲解与落地应.

Python asyncio 异步编程完全指南

目录

  1. 异步编程核心思想
  2. 同步 vs 异步 直观对比
    • 网络请求对比案例
    • 简化Demo(Hello→World)
  3. 协程基础
    • 协程概念与特点
    • async/await 关键字详解
    • 协程函数示例(单个/多个任务)
  4. 事件循环(Event Loop)
    • 核心原理
    • 手动配置事件循环示例
  5. 异步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(异步) 异步订单系统 跟踪每个异步任务的上下文,确保请求与响应一一对应

完整代码

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」的双任务对比,快速理解异步并发的执行逻辑。

运行效果

简化Demo耗时对比

完整代码

import asyncio
import time

# ---------------------- 异步版本 ----------------------
async def async_hello():
    print("异步:Hello")
    await asyncio.sleep(1)  # 模拟IO等待,主动让出CPU
    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)  # 阻塞CPU,无法切换任务
    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)最简化的协程(单个任务)

import asyncio

async def my_coroutine():
    print("协程开始执行")
    await asyncio.sleep(1)  # 模拟1秒IO等待
    return "协程执行结果"

# 启动协程(asyncio.run() 会自动创建事件循环)
result = asyncio.run(my_coroutine())
print("协程返回结果:", result)

(2)多任务聚合(统一调度多个协程)

实际开发中需调度多个协程,用 asyncio.gather() 聚合任务,统一处理结果:

import asyncio

async def task(name):
    print(f"【{name}】启动")
    await asyncio.sleep(1)  # 模拟IO等待
    return f"【{name}】完成"

async def main():
    print("===== 主协程启动 =====")
    # 创建3个并发任务
    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的「调度中心」,本质是单线程的无限循环,负责:

  1. 管理所有协程任务的生命周期(启动、暂停、恢复、结束)
  2. 监听IO事件(如网络响应、文件读取完成)
  3. 当任务暂停时,切换到其他就绪任务
  4. 当IO事件完成时,唤醒等待该事件的任务

生动类比

事件循环 = 餐厅「执行总监」:

  • 分配任务给服务员(协程)
  • 监督任务进度(监听IO事件)
  • 当服务员等待(如等菜)时,安排其去服务其他顾客(切换任务)
  • 当菜做好(IO完成)时,通知服务员上菜(唤醒任务)

2. 手动配置事件循环(进阶)

Python 3.7+ 推荐用 asyncio.run() 自动管理事件循环,但也可手动配置(适合复杂场景):

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等待时阻塞事件循环:

import asyncio
import aiofiles

async def read_file(file_path):
    # 异步打开文件(async with 是异步上下文管理器)
    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,但支持异步)

总结

  1. 核心价值:asyncio通过「协程+事件循环」实现单线程并发,解决IO密集型任务的阻塞问题,提升程序响应速度
  2. 关键语法:async def 定义协程,await 暂停等待,asyncio.gather() 聚合任务
  3. 适用场景:网络请求、数据库操作、文件读写等IO密集型场景
  4. 避坑点:不混用阻塞式IO库,CPU密集型任务优先用多进程(multiprocessing)或 concurrent.futures
posted on 2025-12-01 11:36  28的博客  阅读(7)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3

摘自:28.7的博客

蜀ICP备2025124055号-2