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
会阻塞主线程,直到所有任务都执行完毕。
执行流程总结:
func1
和func2
是两个异步函数,它们分别会打印数字并暂停2秒钟。
- 这些函数被封装成任务并添加到事件循环中。
- 事件循环会调度这些任务并在适当的时机执行它们。由于
asyncio.sleep
是非阻塞的,所以在等待的2秒钟里,事件循环可以自由地执行其他任务。
- 最终,这两个任务会并发地运行,所以在实际运行时,程序在总共大约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
的结构相似,分别输出3
和4
,并在中间暂停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.run
、create_task
等新的推荐方法,这段代码可以避免在Python 3.8及以上版本中出现弃用警告,同时保持代码的现代性和可读性。
协程的意义
在一个线程中如果遇到IO等待时间,线程不会傻傻等,而是利用空闲时间去干其他事情
案例:下载三张图片
部分代码知识点后面文章会说到,这里看不懂没关系,等学完后面再回来看前面就都会看懂
普通方法
协程方法
代码说明:
aiohttp
是一个异步HTTP客户端库,允许你通过异步方式发送HTTP请求。
asyncio
是Python的标准库,支持异步编程,它提供了事件循环和各种异步操作工具。
- 这定义了一个异步函数
fetch
,它接受两个参数:session
(一个aiohttp.ClientSession
对象)和url
(要下载内容的URL)。
async def
是定义异步函数的语法,使得函数可以使用await
关键字。
- 输出一条消息到控制台,指示将要发送请求的URL。这对于调试或了解代码进展非常有用。
- 使用
aiohttp
中的session.get
方法发送一个GET请求到指定的url
。verify_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
函数完成。
打赏
如果您觉得我的内容对你有所帮助,不要吝啬你的一键三连!如果你有能力的话也可以通过下面请我喝杯咖啡~金额您随意~如果对文章内容有任何疑问,欢迎加入群组联系我~
- 作者:Don Mark
- 链接:null/article/f1bb0f06-57a6-4e2d-a5b8-9086b3994954
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。