asyncio 库核心方法详解
asyncio 是 Python 用于编写并发代码的库,使用 async/await 语法。它特别适合 IO 密集型和高并发网络应用。下面我将详细讲解 asyncio 的核心方法。
1. 事件循环 (Event Loop)
事件循环是 asyncio 的核心,负责调度和执行异步任务。
主要方法:
asyncio.get_event_loop()- 获取当前事件循环asyncio.set_event_loop(loop)- 设置当前事件循环asyncio.new_event_loop()- 创建新的事件循环loop.run_until_complete(future)- 运行直到 future 完成loop.run_forever()- 一直运行,直到调用loop.stop()loop.stop()- 停止事件循环loop.close()- 关闭事件循环loop.is_running()- 检查事件循环是否正在运行loop.is_closed()- 检查事件循环是否已关闭
import asyncio
async def example_coroutine(name, seconds):
"""示例协程函数"""
print(f"协程 {name} 开始运行,将等待 {seconds} 秒")
await asyncio.sleep(seconds)
print(f"协程 {name} 完成")
return f"{name}-结果"
def main():
# 创建一个新的事件循环
loop = asyncio.new_event_loop()
try:
# 设置为当前线程的事件循环
asyncio.set_event_loop(loop)
# 检查事件循环状态
print(f"事件循环正在运行吗?: {loop.is_running()}") # False
print(f"事件循环已关闭吗?: {loop.is_closed()}") # False
# 创建几个协程任务
coro1 = example_coroutine("任务A", 2)
coro2 = example_coroutine("任务B", 1)
# 将协程包装为Future/Task
task1 = loop.create_task(coro1)
task2 = asyncio.ensure_future(coro2)
# 运行直到所有任务完成
print("开始运行事件循环...")
loop.run_until_complete(asyncio.gather(task1, task2))
# 获取任务结果
print(f"任务1结果: {task1.result()}")
print(f"任务2结果: {task2.result()}")
# 演示 run_forever 和 stop
async def stop_after(seconds):
await asyncio.sleep(seconds)
loop.stop()
print("\n演示 run_forever 和 stop...")
loop.create_task(example_coroutine("后台任务", 1))
loop.create_task(stop_after(3)) # 只要loop不关闭就不会结束运行,而asyncio.gather(task1, task2)只要所有的task执行结束就会停止
loop.run_forever()
finally:
# 关闭事件循环
if not loop.is_closed():
loop.close()
print(f"事件循环已关闭吗?: {loop.is_closed()}") # True
if __name__ == "__main__":
main()
>>>
事件循环正在运行吗?: False
事件循环已关闭吗?: False
开始运行事件循环...
协程 任务A 开始运行,将等待 2 秒
协程 任务B 开始运行,将等待 1 秒
协程 任务B 完成
协程 任务A 完成
任务1结果: 任务A-结果
任务2结果: 任务B-结果
演示 run_forever 和 stop...
协程 后台任务 开始运行,将等待 1 秒
协程 后台任务 完成
事件循环已关闭吗?: True
2. 协程 (Coroutines)
协程是 asyncio 的基本执行单元,使用 async def 定义。
主要方法:
asyncio.coroutine(func)- 将生成器函数标记为协程(旧式)asyncio.iscoroutine(obj)- 检查对象是否是协程asyncio.iscoroutinefunction(func)- 检查函数是否是协程函数
3. Tasks 和 Futures
Future
Future 代表异步操作的最终结果。
asyncio.Future()- 创建一个 Future 对象future.done()- 检查是否完成future.result()- 获取结果(如果未完成会阻塞)future.exception()- 获取异常future.add_done_callback(cb)- 添加完成回调
Task
Task 是 Future 的子类,用于调度协程的执行。
asyncio.create_task(coro)- 将协程包装为 Task 并调度执行asyncio.ensure_future(obj)- 确保对象是 Future/Tasktask.cancel()- 取消任务task.cancelled()- 检查是否被取消
4. 运行和等待
asyncio.run(coro)- 运行协程(Python 3.7+)asyncio.gather(*coros_or_futures)- 并发运行多个协程asyncio.wait(fs)- 等待一组 Future 完成asyncio.wait_for(fut, timeout)- 带超时的等待asyncio.shield(fut)- 防止任务被取消
示例代码
from time import sleep
import asyncio
import time
import random
async def greet(name):
print("Hello, " + name)
await asyncio.sleep(2)
print("Goodbye, " + name)
async def seed_coroutine():
print('Seeding...')
await send_request()
print('Done Seeding')
async def send_request():
print('Sending request...')
sleep_time = random.randint(5, 10)
print(f'Sleeping for {sleep_time} seconds...')
await asyncio.sleep(sleep_time)
print('Request sent')
async def main():
start_time = time.time()
task1 = asyncio.create_task(greet("Alice")) # 创建任务,用于并发执行多个协程任务
task2 = asyncio.create_task(greet("Bob"))
await asyncio.gather(task1, task2) # 协调任务,用于等待多个协程任务的全部完成
print(f"Time elapsed: {time.time() - start_time} seconds")
task3 = asyncio.create_task(seed_coroutine())
task4 = asyncio.create_task(seed_coroutine())
await asyncio.gather(task3, task4)
print(f"Time elapsed: {time.time() - start_time} seconds")
# 运行主函数
if __name__ == "__main__":
asyncio.run(main())
>>>
Hello, Alice
Hello, Bob
Goodbye, Alice
Goodbye, Bob
Time elapsed: 2.001737117767334 seconds
Seeding...
Sending request...
Sleeping for 6 seconds...
Seeding...
Sending request...
Sleeping for 6 seconds...
Request sent
Done Seeding
Request sent
Done Seeding
Time elapsed: 8.004700183868408 seconds
5. 同步原语
asyncio 提供了类似于 threading 的同步原语:
asyncio.Lock()- 互斥锁asyncio.Event()- 事件asyncio.Condition()- 条件变量asyncio.Semaphore()- 信号量asyncio.BoundedSemaphore()- 有界信号量
6. 网络和子进程
asyncio.open_connection()- 打开 TCP 连接asyncio.start_server()- 启动 TCP 服务器asyncio.create_subprocess_exec()- 创建子进程asyncio.create_subprocess_shell()- 通过 shell 创建子进程
7. 实用工具
asyncio.sleep(delay)- 异步休眠asyncio.get_running_loop()- 获取当前运行的事件循环asyncio.current_task()- 获取当前任务asyncio.all_tasks()- 获取所有任务
最佳实践
实践示例
简易IO流
- 异步字节流
import asyncio
class AsyncBytesIO:
"""简易异步字节流实现"""
def __init__(self):
self._buffer = bytearray()
self._eof = False
self._waiters = []
async def write(self, data):
"""异步写入数据"""
if self._eof:
raise IOError("Stream closed")
self._buffer.extend(data)
# 唤醒所有等待读取的协程
for fut in self._waiters:
if not fut.done():
fut.set_result(None)
self._waiters.clear()
async def read(self, n=-1):
"""异步读取数据"""
while not self._buffer and not self._eof:
# 等待数据到达
fut = asyncio.get_running_loop().create_future()
self._waiters.append(fut)
try:
await fut
except:
self._waiters.remove(fut)
raise
if n < 0 or n > len(self._buffer):
data = bytes(self._buffer)
self._buffer.clear()
else:
data = bytes(self._buffer[:n])
del self._buffer[:n]
return data
async def close(self):
"""关闭流"""
self._eof = True
for fut in self._waiters:
if not fut.done():
fut.set_result(None)
注意
-
尽量使用
asyncio.run()而不是手动管理事件循环 -
使用
create_task()来调度协程 -
避免在协程中使用阻塞 IO 操作
-
合理使用
asyncio.gather()来并发运行多个协程 -
注意异常处理,使用
try/except捕获协程中的异常
asyncio 提供了强大的异步编程能力,理解这些核心方法是掌握 Python 异步编程的关键。
run_forever() 方法与run_until_complete(gather())对比
| 行为特征 | run_forever() | run_until_complete(gather()) |
|---|---|---|
| 停止条件 | 必须显式调用 loop.stop() | 所有task完成自动停止 |
| 任务监控 | 不自动监控任务完成状态 | 显式监控指定任务的完成状态 |
| 适用场景 | 长期运行的服务 | 有限任务的批量执行 |
| 任务结束后 | 事件循环继续空转 | 事件循环自动结束 |
| 是否需要清理 | 需要手动停止和关闭循环 | 自动管理循环生命周期 |
936

被折叠的 条评论
为什么被折叠?



