异步编程是一种高效的并发编程范式,特别适用于 I/O 密集型的应用(如网络请求、文件读写、数据库操作等)。它的核心思想是:当遇到需要等待的操作时,不是让程序“干等”,而是暂停当前任务,去执行其他可以立即运行的任务,等到那个等待的操作完成后,再回来继续执行。
1. 核心概念与关键字
async
- 定义异步函数
-
在
def
关键字前加上async
,这个函数就变成了一个“异步函数”或“协程函数”。 -
调用异步函数时,它会立即返回一个协程对象,但函数体内的代码并不会立即执行。
-
异步函数内部可以使用
await
关键字。
async def my_async_function():return "Hello, Async World!"# 调用它不会直接执行,而是返回一个协程对象 coroutine = my_async_function() print(coroutine) # 输出:<coroutine object my_async_function at 0x...>
await
- 等待异步操作完成
-
await
后面必须跟一个可等待对象,最常见的就是另一个协程。 -
当执行到
await
时,当前协程会暂停,并将控制权交还给事件循环。事件循环会去执行其他任务。 -
直到
await
后面的操作完成,事件循环才会在适当的时候回来,从这个await
之后的地方继续执行当前协程。 -
await
只能在async
定义的函数内部使用。
async def say_after(delay, what):await asyncio.sleep(delay) # 模拟一个耗时的I/O操作print(what)async def main():print("Started")await say_after(1, 'Hello') # 等待这个协程完成await say_after(1, 'World') # 再等待这个协程完成print("Finished")
2. 事件循环 - 异步引擎
事件循环是异步编程的“心脏”。它负责管理和调度所有协程,当某个协程因 await
而暂停时,事件循环就去找另一个可以运行的协程来执行。
在大多数情况下,你不需要直接操作事件循环,asyncio.run()
会帮你管理。
import asyncioasync def main():# ... 你的异步代码 ...# 这是运行异步程序的推荐方式(Python 3.7+) asyncio.run(main())
asyncio.run()
负责创建一个新的事件循环,运行你的主协程,并在完成后关闭循环。
3. 并发执行任务
异步的强大之处在于并发。我们可以创建多个任务,让它们在事件循环中并发执行。
asyncio.create_task()
-
它接受一个协程,并将其“封装”成一个
Task
对象,并立即排入事件循环等待执行。 -
Task
是Future
的子类,代表一个“正在进行中”的计算。
import asyncioasync def say_after(delay, what):await asyncio.sleep(delay)print(what)async def main():# 创建两个任务,它们会并发执行task1 = asyncio.create_task(say_after(1, 'Hello'))task2 = asyncio.create_task(say_after(1, 'World'))print("Started")# 等待两个任务都完成await task1await task2print("Finished") # 总共耗时约1秒,而不是2秒asyncio.run(main())
输出:
Started (等待约1秒后) Hello World Finished
asyncio.gather()
-
用于并发运行多个可等待对象,并收集它们的结果。
-
它返回一个包含所有结果的列表(顺序与传入顺序一致)。
import asyncioasync def fetch_data(id, delay):print(f"Task {id} started")await asyncio.sleep(delay)print(f"Task {id} finished")return f"Data from {id}"async def main():# 并发执行三个任务,并等待它们全部完成results = await asyncio.gather(fetch_data(1, 2),fetch_data(2, 1), # 这个先完成fetch_data(3, 3),)print("All tasks done:", results)asyncio.run(main())
输出:
Task 1 started
Task 2 started
Task 3 started
Task 2 finished
Task 1 finished
Task 3 finished
All tasks done: ['Data from 1', 'Data from 2', 'Data from 3']
4. 可等待对象
在 Python 异步中,有三种主要类型的对象可以在 await
表达式中使用:
-
协程:由
async def
定义的函数返回的对象。 -
Task:由
asyncio.create_task()
等函数创建,用于并发调度协程。 -
Future:一个低层次的、代表异步操作最终结果的对象。
Task
是Future
的子类。通常我们不需要直接创建Future
。
总结
概念/语法 | 作用 |
---|---|
async def |
定义一个异步函数(协程) |
await |
暂停当前协程,等待一个异步操作完成 |
asyncio.run() |
运行主异步函数(管理事件循环) |
asyncio.create_task() |
将协程包装成任务,并发执行 |
asyncio.gather() |
并发运行多个任务并收集结果 |
asyncio.sleep() |
异步的等待(替代 time.sleep ) |
事件循环 | 异步程序的调度中心 |