
一、为什么需要异步编程?同步编程的痛点

在同步编程模式下,程序按照顺序依次执行任务,当前任务未完成时,后续任务只能等待。例如,当程序发起一个网络请求获取数据时,在数据返回之前,整个程序都会处于阻塞状态,无法执行其他任务。这就好比在餐厅排队点餐,前面的人点餐速度很慢,后面的人只能干等着,浪费了大量时间。
假设有一个程序需要依次执行三个网络请求,每个请求耗时 1 秒,那么整个程序执行完就需要 3 秒。如果这三个请求之间没有依赖关系,完全可以同时发起请求,在等待数据返回的过程中去处理其他任务,这样就能大大缩短整体执行时间。而异步编程,正是解决这类问题的关键!
二、初识 asyncio 库:异步编程的基石

asyncio是 Python 用于编写异步程序的标准库,它提供了一系列工具和机制,让开发者能够轻松实现异步代码。其核心概念主要包括以下几个方面:
1. 协程(Coroutine)
协程是asyncio中最基础的单元,它是一种特殊的函数,通过async关键字定义。与普通函数不同,协程函数在执行过程中可以通过await关键字暂停执行,让出控制权,等待其他任务完成后再继续执行。例如:
import asyncio
async def say_hello():print("Hello")await asyncio.sleep(1) # 模拟耗时操作print("World")
asyncio.run(say_hello())
在上述代码中,say_hello是一个协程函数,当执行到await asyncio.sleep(1)时,协程会暂停 1 秒,期间其他任务可以继续执行,1 秒后协程恢复执行,打印出World。
2. 事件循环(Event Loop)
事件循环是asyncio的核心,它负责协调和调度协程的执行。事件循环会不断检查是否有可执行的协程任务,当协程遇到await语句时,事件循环会暂停该协程的执行,并将控制权转移到其他可执行的协程。只有当await的任务完成后,事件循环才会重新唤醒协程继续执行。
可以把事件循环想象成一个忙碌的 “调度员”,它手里拿着所有协程的 “任务清单”,按照一定的规则安排协程执行,确保程序高效运行。
3. 任务(Task)
任务是对协程的进一步封装,用于在事件循环中管理协程的执行。通过asyncio.create_task()方法可以将协程包装成任务,这样事件循环就能更好地调度和监控协程的执行状态。例如:
import asyncioasync def task_function():for i in range(3):print(f"Task running: {i}")await asyncio.sleep(1)async def main():task = asyncio.create_task(task_function())await asyncio.sleep(2) # 模拟其他操作print("Main function continues")await task # 等待任务完成asyncio.run(main())
在这个例子中,task_function是一个协程,通过asyncio.create_task()将其创建为任务,在main协程中可以对任务进行管理和等待。
三、asyncio 实战:并发执行多个任务

下面我们通过一个实际案例,来展示如何使用asyncio并发执行多个任务,体验异步编程带来的效率提升。假设我们需要同时发起多个网络请求获取数据,使用异步编程可以在等待请求返回的过程中,执行其他任务,而不是傻傻等待。
import asyncioimport aiohttp # 用于异步网络请求的库async def fetch_data(session, url):async with session.get(url) as response:return await response.json()async def main():urls = ["https://api.example.com/data1","https://api.example.com/data2","https://api.example.com/data3"]async with aiohttp.ClientSession() as session:tasks = [fetch_data(session, url) for url in urls]results = await asyncio.gather(*tasks)print(results)asyncio.run(main())
在上述代码中,fetch_data协程负责发起网络请求并获取数据,main协程中通过列表推导式创建了多个任务,然后使用asyncio.gather()方法并发执行这些任务,并等待所有任务完成后获取结果。相比同步执行多个网络请求,这种方式能显著减少整体执行时间。
四、asyncio 的应用场景

asyncio库在很多场景下都能发挥巨大作用:
网络请求:在处理大量网络请求时,如爬虫程序、API 调用等,异步编程可以大幅提高数据获取效率。
文件读写:当程序需要频繁进行文件读写操作时,异步方式可以避免因 I/O 操作阻塞而浪费时间。
WebSocket 通信:在实现 WebSocket 服务器或客户端时,asyncio能轻松处理多个连接的并发请求。
五、总结

通过本文的学习,我们了解了 Python 异步编程的重要性,深入认识了asyncio库的核心概念,包括协程、事件循环和任务,并通过实际案例体验了异步编程带来的效率提升。asyncio库为我们提供了强大的异步编程能力,让 Python 程序在处理 I/O 密集型任务时更加高效。


