🗒️Python asyncio高性能异步编程1—协程
00 分钟
2024-8-26
2024-8-26
type
status
date
slug
summary
tags
category
icon
password

协程

协程不是计算机提供,而是由程序员人为创造出来的,就是通过一个线程实现代码块相互切换运行
协程就是func1执行一点再换到func2再执行一点然后再换到func1,一直到两个程序执行完毕
 

实现协程

asyncio模块

当然,以下是对这段代码的逐行解释:
  • 这一行导入了Python的asyncio库。asyncio是Python用于编写并发代码的库,主要用于处理I/O绑定的任务,比如网络请求、文件读取等。
  • @asyncio.coroutine 是一个装饰器,用来将func1函数定义为一个协程。协程是可以在执行过程中暂停并在稍后恢复的函数,这样的功能使得我们能够编写异步代码。
  • def func1() 定义了一个名为 func1 的函数。
  • print(1) 输出数字 1 到控制台。
  • yield from asyncio.sleep(2) 是一个异步操作,它会暂停协程的执行2秒钟,而不是阻塞整个程序。asyncio.sleep(2) 本质上是一个延迟2秒的异步操作。在这2秒内,事件循环可以去执行其他任务。
  • print(2) 在2秒钟的暂停之后,输出数字 2 到控制台。
  • 这段代码与 func1 的结构相似,只是打印了不同的数字。
  • print(3) 输出数字 3 到控制台。
  • yield from asyncio.sleep(2) 同样暂停协程2秒钟,允许事件循环去执行其他任务。
  • print(4) 在2秒钟的暂停之后,输出数字 4 到控制台。
  • 这一段代码创建了一个任务列表 tasks
  • asyncio.ensure_future(func1())func1 的协程包装成一个任务(Task)。任务是由事件循环调度执行的协程,ensure_future 函数会立即安排该协程的执行,并返回一个Task对象。
  • asyncio.ensure_future(func2()) 类似地将 func2 协程包装成一个任务。
  • 这些任务会被添加到 tasks 列表中。
  • loop = asyncio.get_event_loop() 获取当前的事件循环对象。事件循环是asyncio库的核心,负责管理和调度所有的异步任务。
  • loop.run_until_complete() 会运行事件循环,直到传入的任务(或多个任务)完成。
  • asyncio.wait(tasks) 会等待 tasks 列表中的所有任务完成。run_until_complete 会阻塞主线程,直到所有任务都执行完毕。

执行流程总结:

  1. func1func2 是两个异步函数,它们分别会打印数字并暂停2秒钟。
  1. 这些函数被封装成任务并添加到事件循环中。
  1. 事件循环会调度这些任务并在适当的时机执行它们。由于asyncio.sleep是非阻塞的,所以在等待的2秒钟里,事件循环可以自由地执行其他任务。
  1. 最终,这两个任务会并发地运行,所以在实际运行时,程序在总共大约2秒的时间内,按顺序输出1、3、2、4。
 
 

async & await关键字(现代使用的方法)

逐行解释改代码:

  • 这一行保持不变,导入asyncio库。
  • 使用async def来定义一个协程函数func1@coroutine装饰器已经在Python 3.8中被弃用,因此使用async是推荐的做法。
  • 这一行仍然输出数字 1 到控制台。
  • 使用await关键字来暂停协程的执行,同时允许事件循环去执行其他任务。await是异步编程中的核心概念,表示等待一个耗时的操作完成。
  • 在2秒钟的暂停之后,输出数字 2 到控制台。
  • func2的定义方式与func1相同,也是一个协程函数,逻辑相同。
  • func2的代码与func1的结构相似,分别输出34,并在中间暂停2秒。
  • 定义一个名为main的协程函数。这个函数将所有任务放在一起执行。
  • 使用asyncio.create_task来创建任务。与之前的ensure_future不同,create_task是Python 3.7引入的,并且是推荐的方式。它会立即安排协程的执行并返回一个任务对象。
  • asyncio.gather会并发地运行多个任务,并等待它们全部完成。tasks表示将任务列表解包成多个参数传递给gather
  • asyncio.run是Python 3.7引入的一个新函数,它负责启动事件循环并运行指定的协程,最终自动关闭事件循环。它是运行异步代码的推荐方式,尤其是在主程序中。

总结:

  • 通过将@coroutine替换为async def,并使用asyncio.runcreate_task等新的推荐方法,这段代码可以避免在Python 3.8及以上版本中出现弃用警告,同时保持代码的现代性和可读性。
 
 

协程的意义

在一个线程中如果遇到IO等待时间,线程不会傻傻等,而是利用空闲时间去干其他事情
案例:下载三张图片
 
部分代码知识点后面文章会说到,这里看不懂没关系,等学完后面再回来看前面就都会看懂
 

普通方法

 

协程方法

代码说明:

  • aiohttp 是一个异步HTTP客户端库,允许你通过异步方式发送HTTP请求。
  • asyncio 是Python的标准库,支持异步编程,它提供了事件循环和各种异步操作工具。
  • 这定义了一个异步函数 fetch,它接受两个参数:session(一个 aiohttp.ClientSession 对象)和 url(要下载内容的URL)。
  • async def 是定义异步函数的语法,使得函数可以使用 await 关键字。
  • 输出一条消息到控制台,指示将要发送请求的URL。这对于调试或了解代码进展非常有用。
  • 使用 aiohttp 中的 session.get 方法发送一个GET请求到指定的 urlverify_ssl=False 意味着在进行请求时不验证SSL证书,这在某些情况下可能是必要的,但通常建议启用SSL验证以确保安全性。
  • async with 是一个异步上下文管理器,它确保在代码块结束后资源能够正确关闭,例如在此处会自动关闭HTTP连接。
  • 使用 await 关键字读取HTTP响应的内容,并将其存储在 content 变量中。await 表示等待这个异步操作完成,这里读取响应内容时可能会涉及I/O操作,因此是异步的。
  • 使用 rsplit('_', 1) 对URL字符串进行分割,并取最后一个分割后的部分作为文件名。这通常是为了提取URL中的最后一部分(通常是文件名或ID),例如在URL中常见的文件名。
  • 使用Python的内建 open 函数以二进制写入模式 ('wb') 打开一个文件,文件名由前面的步骤得到。with 是上下文管理器的语法,它确保文件在写入完成后被正确关闭。
  • 将下载的内容 (content) 写入到刚才打开的文件中。
  • 定义了一个异步函数 main,它是程序的主要入口。
  • 创建一个 aiohttp.ClientSession 对象并使用异步上下文管理器确保它在使用后正确关闭。ClientSession 对象管理和保持底层连接的连接池,适合频繁发送请求的情况。
  • 定义一个包含三个URL字符串的列表,列表中的每个URL指向一个要下载的图像。
  • 使用列表推导式创建一个任务列表。asyncio.create_task(fetch(session, url)) 会调度 fetch 协程并返回一个 Task 对象,Task 是一个包装了协程的对象,它可以被调度和执行。
  • 这里每个URL都会创建一个 fetch 任务,任务会并发执行。
  • await 等待所有任务完成。asyncio.wait(tasks) 会并发执行所有任务,并等待它们全部完成。
  • 这是一个常见的Python习惯用法,用于判断当前脚本是否作为主程序运行。
  • asyncio.run(main()) 是Python 3.7及以上版本中推荐的启动异步代码的方法,它会执行 main 函数并启动事件循环,直到 main 函数完成。
 
 
 
 

打赏

如果您觉得我的内容对你有所帮助,不要吝啬你的一键三连!如果你有能力的话也可以通过下面请我喝杯咖啡~金额您随意~如果对文章内容有任何疑问,欢迎加入群组联系我~
notion image
上一篇
redis数据库10— redis实战案例
下一篇
Python asyncio高性能异步编程2