跳转至

Python 异步编程实践

Python异步编程允许你在执行I/O操作(如网络请求、文件操作)时不阻塞主线程,从而提高程序的效率。本文将介绍Python中的异步编程基础和实践案例。

异步编程基础

什么是异步编程?

异步编程是一种编程模式,它允许程序在等待I/O操作完成时继续执行其他任务,而不是一直等待直到操作完成。

Python中的异步编程

Python 3.5+ 提供了以下异步编程支持:

  • async/await 语法
  • asyncio
  • 异步上下文管理器和迭代器

asyncio 基本使用

创建协程

import asyncio

async def hello_world():
    print("Hello")
    await asyncio.sleep(1)  # 模拟I/O操作
    print("World")

# 运行协程
asyncio.run(hello_world())

并发运行多个协程

import asyncio
import time

async def say(what, delay):
    await asyncio.sleep(delay)
    print(what)

async def main():
    print(f"开始时间: {time.strftime('%X')}")

    # 并发运行协程
    await asyncio.gather(
        say("任务1", 1),
        say("任务2", 2),
        say("任务3", 3)
    )

    print(f"结束时间: {time.strftime('%X')}")

asyncio.run(main())

实际应用案例

异步网络请求

使用aiohttp库进行异步HTTP请求:

import asyncio
import aiohttp
import time

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    urls = [
        "https://example.com",
        "https://python.org",
        "https://github.com",
        "https://stackoverflow.com",
        "https://pypi.org"
    ]

    start_time = time.time()

    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, url) for url in urls]
        results = await asyncio.gather(*tasks)

        for url, result in zip(urls, results):
            print(f"{url}: 获取到 {len(result)} 字节的数据")

    end_time = time.time()
    print(f"总耗时: {end_time - start_time:.2f} 秒")

asyncio.run(main())

异步文件操作

使用aiofiles库进行异步文件操作:

import asyncio
import aiofiles

async def read_file(file_path):
    async with aiofiles.open(file_path, mode='r') as f:
        return await f.read()

async def write_file(file_path, content):
    async with aiofiles.open(file_path, mode='w') as f:
        await f.write(content)

async def main():
    # 读取文件
    content = await read_file('input.txt')

    # 处理内容
    processed_content = content.upper()

    # 写入文件
    await write_file('output.txt', processed_content)

    print("文件处理完成")

asyncio.run(main())

异步与多线程对比

异步编程和多线程都可以实现并发,但它们有很大区别:

特性 异步编程 多线程
切换成本
内存占用
并行处理 不支持 支持
复杂度 中等
适用场景 I/O密集型 CPU密集型

最佳实践

  1. 使用适当的库:如aiohttp(网络),aiofiles(文件),asyncpg(数据库)等
  2. 避免阻塞操作:在异步函数中不要使用阻塞操作,如time.sleep()
  3. 合理分组任务:使用asyncio.gather()asyncio.TaskGroup分组任务
  4. 使用超时控制:对可能耗时较长的操作设置超时
  5. 错误处理:合理处理异步操作中的异常

结语

Python异步编程在处理I/O密集型任务时非常高效,但也不是万能的。选择正确的工具来解决问题,有时候同步代码反而更简单易读。掌握异步编程思想和技巧,能帮助你写出更高效的Python程序。