asyncio
是 Python 标准库中用于
异步编程 和
并发任务 管理的核心库。它的基础是事件循环,用来调度协程(coroutines),让它们能够非阻塞地并发执行。这种编程模型在处理大量 I/O 密集型任务时非常高效,如网络操作、文件读写等。
一、asyncio
的核心概念
-
协程(Coroutines):
- 协程是
asyncio
中的基本单元,使用async def
定义。 - 使用
await
调用另一个协程,表示暂停当前协程,等待被调用的协程完成后再继续。 - 它们是异步执行的,不会阻塞整个程序。
async def my_coroutine(): print("开始") await asyncio.sleep(1) # 模拟异步操作 print("结束")
- 协程是
-
事件循环(Event Loop):
asyncio
的核心,管理协程的执行顺序。- 事件循环负责调度多个协程,轮流执行它们。它允许一个协程在等待时,另一个协程可以使用 CPU 进行其他工作。
- 使用
asyncio.run()
启动事件循环。
async def main(): await my_coroutine() asyncio.run(main()) # 启动事件循环
-
任务(Tasks):
- 任务是协程的一种封装,它表示一个并发执行的协程。使用
asyncio.create_task()
来创建任务。 - 任务会立即运行,允许多个任务同时进行。
async def my_task(): print("任务执行") await asyncio.sleep(1) async def main(): task = asyncio.create_task(my_task()) # 创建并发任务 await task asyncio.run(main())
- 任务是协程的一种封装,它表示一个并发执行的协程。使用
-
Future:
Future
是一个低层次的对象,表示一个将来会有结果的异步操作。协程与任务本质上也是基于Future
的封装。- 一般不需要直接操作
Future
,而是通过协程或任务来间接使用它们。
二、asyncio
的常见用法
-
await
和async def
:await
用于在协程中等待其他异步操作完成,async def
用于定义协程。
async def fetch_data(): await asyncio.sleep(2) # 模拟网络请求 return "数据" async def main(): result = await fetch_data() print(result) asyncio.run(main())
-
并发任务:
asyncio.create_task()
和asyncio.gather()
:asyncio.create_task()
创建一个并发任务,立即执行。asyncio.gather()
可以同时执行多个协程,返回它们的结果。
async def task1(): await asyncio.sleep(2) return "任务1完成" async def task2(): await asyncio.sleep(1) return "任务2完成" async def main(): result1 = asyncio.create_task(task1()) result2 = asyncio.create_task(task2()) await result1 await result2 print("所有任务完成") asyncio.run(main())
-
同步等待多个任务:
asyncio.gather()
:- 同时启动多个协程,并等待它们全部完成。
async def task1(): await asyncio.sleep(2) return "任务1完成" async def task2(): await asyncio.sleep(1) return "任务2完成" async def main(): results = await asyncio.gather(task1(), task2()) print(results) asyncio.run(main())
-
超时处理:
asyncio.wait_for()
:- 可以为一个协程设置超时时间,防止协程执行时间过长。
async def task(): await asyncio.sleep(3) return "完成" async def main(): try: result = await asyncio.wait_for(task(), timeout=2) # 设置2秒超时 print(result) except asyncio.TimeoutError: print("任务超时") asyncio.run(main())
-
同步等待:
asyncio.sleep()
:- 用于模拟异步任务中的延迟,或者简单地让协程在特定时间内暂停。
async def main(): print("开始") await asyncio.sleep(2) # 暂停2秒 print("结束") asyncio.run(main())
-
同步进程:
asyncio.run_in_executor()
:- 将阻塞的操作(如文件读写、网络请求等)交给线程池或进程池,避免阻塞事件循环。
import asyncio import concurrent.futures def blocking_task(): print("阻塞任务执行中...") return "完成" async def main(): loop = asyncio.get_running_loop() with concurrent.futures.ThreadPoolExecutor() as pool: result = await loop.run_in_executor(pool, blocking_task) print(result) asyncio.run(main())
三、asyncio
中的同步原语
-
asyncio.Event()
:- 用于在线程或协程之间传递简单的信号,允许一个或多个协程等待某个事件发生。
async def waiter(event): print("等待事件...") await event.wait() print("事件触发!") async def main(): event = asyncio.Event() waiter_task = asyncio.create_task(waiter(event)) await asyncio.sleep(2) print("触发事件") event.set() await waiter_task asyncio.run(main())
-
asyncio.Lock()
:- 一个异步锁,确保多个协程在同一时间只能有一个协程访问某个资源。
async def task(lock): print("等待锁...") async with lock: # 获取锁 print("获得锁") await asyncio.sleep(2) print("释放锁") async def main(): lock = asyncio.Lock() await asyncio.gather(task(lock), task(lock)) asyncio.run(main())
-
asyncio.Queue()
:- 一个线程安全的异步队列,允许多个生产者和消费者协程安全地传递数据。
async def producer(queue): for i in range(5): await asyncio.sleep(1) await queue.put(i) print(f"生产者放入: {i}") async def consumer(queue): while True: item = await queue.get() print(f"消费者取出: {item}") if item == 4: break async def main(): queue = asyncio.Queue() await asyncio.gather(producer(queue), consumer(queue)) asyncio.run(main())
四、asyncio
中的网络操作
asyncio
还可以用于构建高效的异步网络服务,如 TCP/UDP 服务器和客户端。通过 asyncio.start_server()
和 asyncio.open_connection()
等函数,开发者可以构建异步的网络应用。
async def handle_client(reader, writer):
data = await reader.read(100)
message = data.decode()
print(f"收到消息: {message}")
writer.write(data)
await writer.drain()
writer.close()
async def main():
server = await asyncio.start_server(handle_client, '127.0.0.1', 8888)
async with server:
await server.serve_forever()
asyncio.run(main())
五、asyncio
的调试工具
asyncio.all_tasks()
:查看所有当前活动的任务。asyncio.current_task()
:查看当前正在运行的任务。asyncio.Task.get_stack()
:查看任务的当前堆栈信息,用于调试。
总结
- 协程 是异步执行的基本单元,使用
async def
定义。 - 事件循环 是
asyncio
的核心,用来调度协程和任务。 - 使用 任务 (
asyncio.create_task()
) 和 gather 并发执行多个协程。 asyncio
还提供了丰富的 同步原语(如Event
、Lock
)和高效的 I/O 操作支持。
asyncio
在处理并发 I/O 密集型任务时非常强大,使用它可以避免传统多线程编程中的锁和上下文切换开销。