1、引言
asyncio 是 Python 标准库中的一个库,提供了对异步 I/O 、事件循环、协程和任务等异步编程模型的支持。
asyncio 文档
2、进程、线程、协程
-
线程
线程是操作系统调度的基本单位,同一个进程中的多个线程共享相同的内存空间。线程之间的切换由操作系统内核负责。
特点:共享同一资源空间,切换时有开销,但比进程小,适合 I/O 密集型任务,需要管理资源竞争问题。
-
进程
进程是操作系统资源分配的基本单位,每个进程有独立的内存空间,进程之间不能共享内存,需要通过进程间通信(IPC)。
特点:任务完全独立,互不干扰,各自有自己的资源,切换时开销较大,适合 CPU 密集型任务。
-
协程
协程是由程序自身调度的函数,可以在执行过程中暂停和恢复,协程的切换由程序自身完成,而不是依赖操作系统。
特点:单线程内管理多任务,没有线程切换的开销,适合 I/O 密集型任务,需要程序自己管理任务的切换。
3 、asyncio 的基本使用
3.1 异步函数 和 await
异步函数使用 async def 声明,await 关键字用于等待一个 异步操作完成。
代码案例
import asyncioasync def hello():print("Hello")await asyncio.sleep(2)print("World")asyncio.run(hello())
注意:
- async 声明后,不能直接 say_hello 运行函数
- 现在运行还是会 等待 1s 后执行 print(“World”)
- 协成本质上是事件循环。不是说用了 async await 就会成异步,是需要程序员自己定义任务有哪些协程的。
3.2 任务(Tasks)
任务用于调度和管理协程的执行。
代码示例
import asyncioasync def greet(name):print(f"Hello, {name}")await asyncio.sleep(2)print(f"GoodBye: {name}")async def main():task1 = asyncio.create_task(greet("Tom"))task2 = asyncio.create_task(greet("Jerry"))await task1await task2asyncio.run(main())"""
输出:
Hello, Tom
Hello, Jerry
GoodBye: Tom
GoodBye: Jerry
"""
4、本质
4.1 协程
协程是可以暂停和恢复的函数。与传统的函数不同,协程可以在执行过程中暂停,以便其他协程可以运行。Python 使用 async def 声明协程函数,使用 await 暂停协程的执行。
4.2 事件循环
事件循环是 asyncio 的核心,用于调度 和执行协程。事件循环负责处理异步函数、I/O 事件、定时器等。
4.3 任务 和 Future
任务是协程的高级抽象,用于调度协程的执行。Future 是表示异步操作结果的低级抽象,可以与任务一起使用。
5、高级使用
5.1 混合同步与异步IO
演示如何在异步环境中调用同步函数。
import asyncio# 同步函数
def sync_function():print("执行同步函数")# 异步函数
async def async_function():print("开始执行异步函数")await asyncio.sleep(2) # 模拟异步操作print("异步函数执行完成")# 在异步环境中调用同步函数
async def main():loop = asyncio.get_event_loop()await loop.run_in_executor(None, sync_function)await async_function()asyncio.run(main())"""
输出
执行同步函数
开始执行异步函数
异步函数执行完成
"""
5.2 异步 I/O 中高级处理
import asyncioasync def my_async_function():try:await asyncio.wait_for(asyncio.sleep(5), timeout=3)except asyncio.TimeoutError:print("异步操作超时")asyncio.run(my_async_function())
5.3 异步I/O 中并发限制
有时候,为了避免资源耗尽,需要限制并发任务的数量。Asyncio提供了Semaphore来限制并发量。
asyncio.gather 是 Python 的 asyncio 模块中的一个函数,用于并发运行多个异步任务并收集它们的结果。它允许你将多个协程(或可等待对象)打包在一起,并并发地执行它们。
import asyncioasync def limited_task(sem, num):async with sem:print(f"开始执行任务 {num}")await asyncio.sleep(2)print(f"任务 {num} 执行完成")async def main():sem = asyncio.Semaphore(5)tasks = [limited_task(sem, i) for i in range(10)]await asyncio.gather(*tasks)asyncio.run(main())