目录
- 前言
- 一、异步编程的概念
- 1-1、异步编程
- 1-2、同步 vs 异步
- 1-3、阻塞 vs 非阻塞
- 1-4、并发 vs 并行
- 二、Python 异步编程的主要模块
- 2-1、asyncio
- 2-2、async 和 await 关键字
- 2-3、 aiohttp
- 三、案例分析
- 3-0、安装
- 3-1、基本案例
- 3-2、并发执行多个任务
- 3-3、异常处理
- 3-4、与队列结合
- 总结
前言
Python 异步编程是一种编程方式,用于处理可以并发执行的任务,以提高程序的效率和性能。异步编程允许在一个线程中执行多个任务,通过在某些任务等待 I/O 操作(如文件读写、网络请求等)完成时切换到其他任务,从而更有效地利用 CPU 资源。一、异步编程的概念
1-1、异步编程
异步编程: 是一种编程范式,允许程序在等待某些操作完成时不阻塞线程或进程,继续执行其他任务。这种方式使得资源利用更高效,特别是在 I/O 密集型操作(如网络请求、文件读写等)中表现尤为显著。
1-2、同步 vs 异步
同步 vs 异步
- 同步:任务按顺序执行,一个任务未完成时,后续任务必须等待。这种方式直观但效率较低,尤其在处理 I/O 操作时。
- 异步:任务可以并发执行,一个任务在等待时,其他任务仍可继续进行。这样可以提高资源利用率和程序的响应速度。
1-3、阻塞 vs 非阻塞
阻塞 vs 非阻塞
- 阻塞操作:会使得程序等待操作完成,期间无法执行其他任务。例如,读取文件时,程序会等待文件完全读取后再继续执行。
- 非阻塞操作:操作会立即返回,程序可以继续执行其他任务。例如,发起一个网络请求后,程序可以继续执行其他任务,等待请求完成时再处理结果。
1-4、并发 vs 并行
并发 vs 并行
- 并发:在同一时间段内处理多个任务,不一定是同时进行,但看起来像是同时进行。
- 并行:在同一时刻同时处理多个任务,通常需要多核处理器支持。
二、Python 异步编程的主要模块
2-1、asyncio
asyncio 是 Python 标准库中的一个模块,专门用于编写并发代码。它提供了事件循环、协程、任务和各种 I/O 操作的异步支持。
- 事件循环(Event Loop):asyncio 的核心组件,负责调度和管理协程的执行。事件循环不断运行,检查并执行准备好的任务。
- 协程(Coroutine):使用 async def 定义的函数,可以在等待某个操作完成时挂起并允许其他协程运行。
- 任务(Task):由事件循环管理的协程,通过 asyncio.create_task() 创建,可以并发执行。
- 未来对象(Future):表示一个异步操作的结果,通常不直接使用,而是通过任务和协程间接使用。
2-2、async 和 await 关键字
async 和 await 关键字
- async:用于定义协程函数。协程函数是可以在执行过程中挂起并恢复的函数。
- await:用于暂停协程的执行,等待某个异步操作完成,然后继续执行。await 后面可以跟随一个返回 awaitable 对象(如协程、任务或未来对象)的表达式。注意: 异步函数需要使用 await 关键字进行调用, 如果不使用await,调用异步函数只会返回一个协程对象,函数内部的异步操作不会实际执行。
2-3、 aiohttp
aiohttp 是一个用于构建异步 HTTP 客户端和服务器的库。它基于 asyncio 实现,允许在异步环境中进行高效的 HTTP 通信。
- HTTP 客户端:使用 aiohttp 可以发起异步 HTTP 请求,不阻塞主线程,处理大量并发请求时性能优越。
- HTTP 服务器:aiohttp 提供了构建异步 HTTP 服务器的能力,适用于高并发环境。
三、案例分析
3-0、安装
pip install asyncio
3-1、基本案例
概述: 使用await挂起协程的执行,即模拟的IO操作,直到被等待的任务完成。asyncio.run() 用于启动一个事件循环并运行协程。
import asyncioasync def fetch_data():print("Start fetching data...")await asyncio.sleep(2) # 模拟 I/O 操作,实际应用中可以是网络请求或文件读写print("Data fetched.")return "Data"async def main():print("Main started")result = await fetch_data() # 等待 fetch_data 完成print("Result:", result)print("Main finished")# 获取事件循环并运行 main 协程
asyncio.run(main())
输出:
3-2、并发执行多个任务
概述: 可以使用 asyncio.gather() 或 asyncio.create_task() 来并发执行多个任务
两个任务并发
import asyncioasync def task1():await asyncio.sleep(1)print("Task 1 completed")async def task2():await asyncio.sleep(2)print("Task 2 completed")async def main():tasks = [task1(), task2()]await asyncio.gather(*tasks) # 并发执行所有任务asyncio.run(main())
输出:
多任务并发:
import time
import asyncio# 定义异步函数
async def hello():await asyncio.sleep(1)print('Hello World:%s' % time.time())async def main():tasks = [hello() for i in range(5)]await asyncio.gather(*tasks)if __name__ == '__main__':# 自动创建一个事件循环,运行传递给它的协程,并在运行结束后关闭事件循环。# 这种方法适合简单的脚本和程序,因为它隐藏了事件循环的管理细节。asyncio.run(main())
多任务并发:等价于上边的函数,但是更底层
import time
import asyncio# 定义异步函数
async def hello():await asyncio.sleep(1)print('Hello World:%s' % time.time())if __name__ == '__main__':loop = asyncio.get_event_loop()tasks = [hello() for i in range(5)]# 运行事件循环,直到传递的任务完成。# 我们可以把一些函数(通过 async 定义的函数,称为协程)注册到事件循环上,当满足事件发生的条件时,调用相应的协程函数。# asyncio.wait 和 asyncio.gather的功能类似,但可以更灵活地处理任务完成的顺序。loop.run_until_complete(asyncio.wait(tasks))
多任务并发总结:
- 第二段代码使用 asyncio.run(),这是一个高层次的 API,简化了事件循环的创建、运行和关闭过程。
- 第三段代码手动获取和管理事件循环,更低层次,可以提供更大的灵活性。
3-3、异常处理
概述: 异步函数中的异常处理与同步代码类似,但需要在协程中使用 try、except 块
import asyncioasync def faulty_task():await asyncio.sleep(1)raise ValueError("An error occurred!")async def main():try:await faulty_task()except ValueError as e:print("Caught an exception:", e)asyncio.run(main())
输出:
3-4、与队列结合
概述: 异步编程还支持与异步生成器、队列、锁等高级特性结合使用,以实现更复杂的并发逻辑。
import asyncioasync def producer(queue):for i in range(5):await asyncio.sleep(1)await queue.put(i)print(f"Produced {i}")async def consumer(queue):while True:item = await queue.get()if item is None:breakprint(f"Consumed {item}")queue.task_done()async def main():queue = asyncio.Queue()await asyncio.gather(producer(queue), consumer(queue))await queue.join()asyncio.run(main())
输出:
参考文章:
【测试开发】python系列教程:asyncio模块
理解python异步编程与简单实现asyncio
总结
🤣沉迷于DNF手游无法自拔。