当前位置:首页 > Python > 正文

Python asyncio三种应用方法详解 - 异步编程入门教程

Python asyncio三种应用方法详解

掌握异步编程的核心技巧,提升Python程序性能

1事件循环

asyncio的核心,负责调度和执行协程。它管理所有异步任务,并在适当的时候切换执行。

2async/await

定义协程的关键字。async用于声明异步函数,await用于挂起当前协程,等待其他协程完成。

3Future和Task

Future代表异步操作的最终结果,Task是Future的子类,用于包装协程并管理其执行状态。

什么是Python asyncio?

asyncio是Python标准库中用于编写并发代码的库,使用async/await语法。它提供了一种单线程单进程的并发模型,通过协作式多任务实现高并发性能。

与传统的多线程相比,asyncio的优势在于:

  • 更高效的I/O密集型任务处理
  • 避免了多线程的锁和同步问题
  • 更轻量级的任务切换
  • 清晰的异步代码结构

1 事件循环(Event Loop)应用方法

事件循环是asyncio的核心,负责调度和执行协程。它管理所有异步任务,并在适当的时候切换执行。

基本使用示例

import asyncio

# 定义异步函数
async def main():
    print('Hello')
    await asyncio.sleep(1)  # 模拟I/O操作
    print('World')

# 获取事件循环
loop = asyncio.get_event_loop()

# 运行协程直到完成
loop.run_until_complete(main())

# 关闭事件循环
loop.close()

最佳实践建议

  • 在Python 3.7+中,推荐使用asyncio.run()代替手动管理事件循环
  • 避免在事件循环中运行阻塞代码,这会阻止其他任务执行
  • 使用loop.create_task()来创建并发任务

2 async/await应用方法

async/await是定义协程的关键字。async用于声明异步函数,await用于挂起当前协程,等待其他协程完成。

多个协程并发执行

import asyncio
import time

# 模拟耗时I/O操作
async def fetch_data(task_id, delay):
    print(f"任务 {task_id} 开始,需要 {delay} 秒")
    await asyncio.sleep(delay)
    print(f"任务 {task_id} 在 {time.strftime('%X')} 完成")
    return f"任务 {task_id} 结果"

async def main():
    # 同时启动三个任务
    task1 = asyncio.create_task(fetch_data(1, 2))
    task2 = asyncio.create_task(fetch_data(2, 1))
    task3 = asyncio.create_task(fetch_data(3, 3))
    
    # 等待所有任务完成并收集结果
    results = await asyncio.gather(task1, task2, task3)
    print("所有任务完成:", results)

# Python 3.7+ 推荐用法
asyncio.run(main())

await 使用要点

  • 只能在async函数内部使用
  • 可以等待另一个协程、Task或Future
  • await会暂停当前协程,直到等待的对象完成

async 函数特点

  • 使用async def定义
  • 调用时返回协程对象,不会立即执行
  • 可以包含await表达式、return和yield

3 Future和Task应用方法

Future代表异步操作的最终结果,Task是Future的子类,用于包装协程并管理其执行状态。

使用Future和Task的高级示例

import asyncio

# 使用Future的示例
async def set_future_result(future, value, delay):
    print(f"将在 {delay} 秒后设置Future结果")
    await asyncio.sleep(delay)
    future.set_result(value)

# 使用Task的示例
async def long_running_task(task_id, seconds):
    print(f"任务 {task_id} 开始,将运行 {seconds} 秒")
    for i in range(seconds):
        print(f"任务 {task_id} 进度: {i+1}/{seconds}")
        await asyncio.sleep(1)
    return f"任务 {task_id} 完成"

async def main():
    # 创建Future对象
    future = asyncio.Future()
    
    # 创建任务设置Future的结果
    asyncio.create_task(set_future_result(future, "Future完成!", 2))
    
    # 创建长时间运行的任务
    task1 = asyncio.create_task(long_running_task(1, 4))
    task2 = asyncio.create_task(long_running_task(2, 3))
    
    # 等待Future完成
    future_result = await future
    print("Future结果:", future_result)
    
    # 等待任务完成
    task_result = await asyncio.gather(task1, task2)
    print("任务结果:", task_result)

asyncio.run(main())

关键概念解析

Future对象
  • 表示异步操作的最终结果
  • 当结果可用时,会设置结果值
  • 可以添加完成回调函数
Task对象
  • 是Future的子类
  • 包装一个协程并在事件循环中执行
  • 使用asyncio.create_task()创建

异步编程最佳实践

避免阻塞操作

不要在协程中运行阻塞I/O或CPU密集型操作,这会使事件循环停止。使用run_in_executor执行阻塞操作。

合理设置超时

使用asyncio.wait_for为异步操作设置超时,避免任务永久挂起。

任务取消处理

正确处理任务取消异常(asyncio.CancelledError),确保资源被正确释放。

asyncio三种方法对比

方法 适用场景 复杂度 控制粒度
事件循环 底层控制,框架开发 精细
async/await 日常异步编程 中等
Future/Task 高级异步模式,回调管理 非常精细

"对于大多数应用场景,使用async/await结合Task是最佳选择,它提供了良好的抽象和控制能力。"

© 2023 Python异步编程教程 | 掌握asyncio,提升程序性能

发表评论