Python异步编程实战:asyncio入门到精通

Python的asyncio模块是实现异步编程的核心工具。随着Python 3.5引入async/await语法,异步编程变得越来越流行。本文将从基础概念到高级用法,带你全面掌握asyncio。

一、什么是异步编程

同步 vs 异步

同步编程:代码按照顺序执行,一个任务完成后才开始下一个。如果遇到IO操作(如网络请求、文件读写),程序会阻塞等待。

异步编程:程序可以在等待IO操作时切换执行其他任务,充分利用等待时间,提高程序的整体效率。

为什么需要异步

  1. IO密集型任务:网络请求、文件读写、数据库查询等
  2. 高并发场景:Web服务器、爬虫、API网关等
  3. 资源利用:单线程也能处理大量并发连接

asyncio的优势

  • 单线程运行,无锁竞争
  • 代码可读性好(相比回调地狱)
  • Python官方标准库,无需额外依赖
  • 与同步代码可以共存

二、基础概念

1. 协程(Coroutine)

协程是asyncio的基础。使用 async def 定义协程函数:

import asyncio

async def hello():
    print('Hello')
    await asyncio.sleep(1)  # 异步等待1秒
    print('World')

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

2. await 关键字

await 用于等待一个协程或可等待对象。在await处,程序会挂起并让出控制权:

async def fetch_data():
    print('开始获取数据...')
    await asyncio.sleep(2)  # 模拟网络请求
    print('数据获取完成')
    return {'name': '张三', 'age': 25}

3. 事件循环(Event Loop)

事件循环是asyncio的核心,负责调度和执行协程:

import asyncio

async def main():
    print('主协程开始')
    await asyncio.sleep(1)
    print('主协程结束')

# Python 3.7+
asyncio.run(main())

三、并发执行

1. asyncio.gather()

同时执行多个协程:

import asyncio
import time

async def task(name, delay):
    print(f'任务{name}开始')
    await asyncio.sleep(delay)
    print(f'任务{name}完成')
    return f'{name}的结果'

async def main():
    start = time.time()

    # 并发执行3个任务
    results = await asyncio.gather(
        task('A', 2),
        task('B', 1),
        task('C', 3)
    )

    print(f'所有任务完成,耗时: {time.time() - start:.2f}秒')
    print(f'结果: {results}')

asyncio.run(main())

2. asyncio.create_task()

创建后台任务:

async def background_task():
    while True:
        print('后台任务运行中...')
        await asyncio.sleep(5)

async def main():
    # 创建后台任务
    task = asyncio.create_task(background_task())

    # 主逻辑继续执行
    print('主逻辑执行中...')
    await asyncio.sleep(3)
    print('主逻辑完成')

    # 取消后台任务
    task.cancel()

asyncio.run(main())

四、超时控制

1. asyncio.wait_for()

设置单个协程的超时时间:

async def slow_task():
    await asyncio.sleep(10)
    return '完成'

async def main():
    try:
        result = await asyncio.wait_for(slow_task(), timeout=3.0)
    except asyncio.TimeoutError:
        print('任务超时!')

五、实战示例

1. 异步HTTP请求

使用 aiohttp 库:

import asyncio
import aiohttp

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

async def main():
    urls = [
        'https://httpbin.org/get',
        'https://httpbin.org/ip',
        'https://httpbin.org/user-agent',
    ]

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

        for url, result in zip(urls, results):
            print(f'{url}: {result[:100]}...')

asyncio.run(main())

六、最佳实践

1. 不要在协程中使用阻塞操作

# 错误示范
async def bad_example():
    import time
    time.sleep(5)  # 这会阻塞整个事件循环!

# 正确做法
async def good_example():
    await asyncio.sleep(5)  # 异步等待

2. 使用asyncio.run()作为入口

# Python 3.7+
async def main():
    # 你的异步代码
    pass

if __name__ == '__main__':
    asyncio.run(main())

七、总结

asyncio是Python异步编程的强大工具。掌握它需要理解:

  1. 协程:使用async/await定义和执行
  2. 事件循环:调度和执行协程的核心
  3. 并发执行:gather、create_task、wait
  4. 超时控制:wait_for、shield
  5. 最佳实践:避免阻塞、合理错误处理

异步编程能显著提升IO密集型应用的性能。希望这篇教程对你有帮助!