Python协程方式的实现及意义笔记分享
目录
- 协程
- 1.greenlet实现协程
- 2.yield
- 3.asyncio
- 4.async & awit
- 2.协程的意义
- 小结
协程 协程不是计算机提供的,是程序员认为创造
协程也被称为微线程,是一种用户态的上下文切换技术,简而言之,就是通过一个线程实现代码互相切换执行
实现协程的几种方法:
- 1)greenlet,早期模块
- 2)yield关键字
- 3)asyncio装饰器 (python3.4以后引入的)
- 4)async,await关键字 (python3.5) 推荐
1.greenlet实现协程
greentlet是一个第三方模块,需要提前安装 pip3 install greenlet才能使用。
from greenlet import greenletdef func1():print(1)# 第1步:输出 1gr2.switch()# 第3步:切换到 func2 函数print(2)# 第6步:输出 2gr2.switch()# 第7步:切换到 func2 函数,从上一次执行的位置继续向后执行def func2():print(3)# 第4步:输出 3gr1.switch()# 第5步:切换到 func1 函数,从上一次执行的位置继续向后执行print(4)# 第8步:输出 4gr1 = greenlet(func1)gr2 = greenlet(func2)gr1.switch() # 第1步:去执行 func1 函数
输出的结果:1324
注意:switch中也可以传递参数用于在切换执行时相互传递值。
2.yield
基于Python的生成器的yield和yield form关键字实现协程代码。
def func1():yield 1#第一步执行这里会生成1yield from func2() #这里会跳到func2,然后执行里面的代码,执行完func2函数后会继续以跳转之前的状态继续执行以下代码yield 2def func2():yield 3yield 4# 这里是一个生成器对象f1 = func1()# 遍历执行生成器for item in f1:print(item)
执行结果1342
注:用这种方法比较牵强,真正开发环境中基本不会用这种方法实现协程(yield form关键字是在Python3.3中引入的。)
3.asyncio
【Python协程方式的实现及意义笔记分享】在Python3.4之前官方未提供协程的类库,一般大家都是使用greenlet等其他来实现。在Python3.4发布后官方正式支持协程,即:asyncio模块。
import asyncio#这就是一个用协程实现的函数@asyncio.coroutinedef func1():print(1)yield from asyncio.sleep(2)# 遇到IO耗时操作,自动化切换到tasks中的其他任务print(2)loop = asyncio.get_event_loop()#执行loop.run_until_complete(func1())
同时执行多个协程
import asyncio@asyncio.coroutinedef func1():print(1)yield from asyncio.sleep(2)# 遇到IO耗时操作,自动化切换到tasks中的其他任务print(2)@asyncio.coroutinedef func2():print(3)yield from asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到tasks中的其他任务print(4)tasks = [asyncio.ensure_future( func1() ),asyncio.ensure_future( func2() )]loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))
结果1324
注意:基于asyncio模块实现的协程比之前的要更厉害,因为他的内部还集成了遇到IO耗时操作自动切花的功能。
4.async & awit
async & awit 关键字在Python3.5版本中正式引入,基于他编写的协程代码其实就是 上一示例 的加强版,让代码可以更加简便。
Python3.8之后 @asyncio.coroutine 装饰器就会被移除,推荐使用async & awit 关键字实现协程代码。
import asyncioasync def func1():print(1)await asyncio.sleep(2)print(2)async def func2():print(3)await asyncio.sleep(2)print(4)tasks = [asyncio.ensure_future(func1()),asyncio.ensure_future(func2())]loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))
常用的是:greenlet,async&awit
2.协程的意义 在一个线程中遇到IO耗时,线程不会等待,利用空余的时间去执行其他的方法
2.1爬虫案例
例如:用代码实现下载 url_list 中的图片。
方式一:同步编程实现
import requestsdef download_image(url):print("开始下载:",url)# 发送网络请求,下载图片response = requests.get(url)print("下载完成")# 图片保存到本地文件file_name = url.rsplit('_')[-1]with open(file_name, mode='wb') as file_object:file_object.write(response.content)if __name__ == '__main__':url_list = ['https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg','https://www2.autoimg.cn/newsdfs/g30/M01/3C/E2/120x90_0_autohomecar__ChcCSV2BBICAUntfAADjJFd6800429.jpg','https://www3.autoimg.cn/newsdfs/g26/M0B/3C/65/120x90_0_autohomecar__ChcCP12BFCmAIO83AAGq7vK0sGY193.jpg']for item in url_list:download_image(item)
结果开始下载: https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg下载完成开始下载: https://www2.autoimg.cn/newsdfs/g30/M01/3C/E2/120x90_0_autohomecar__ChcCSV2BBICAUntfAADjJFd6800429.jpg下载完成开始下载: https://www3.autoimg.cn/newsdfs/g26/M0B/3C/65/120x90_0_autohomecar__ChcCP12BFCmAIO83AAGq7vK0sGY193.jpg下载完成
方式二:基于协程的异步编程实现
import aiohttpimport asyncioasync def fetch(session, url):print("发送请求:", url)async with session.get(url, verify_ssl=False) as response:content = await response.content.read()file_name = url.rsplit('_')[-1]with open(file_name, mode='wb') as file_object:file_object.write(content)async def main():async with aiohttp.ClientSession() as session:url_list = ['https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg','https://www2.autoimg.cn/newsdfs/g30/M01/3C/E2/120x90_0_autohomecar__ChcCSV2BBICAUntfAADjJFd6800429.jpg','https://www3.autoimg.cn/newsdfs/g26/M0B/3C/65/120x90_0_autohomecar__ChcCP12BFCmAIO83AAGq7vK0sGY193.jpg']tasks = [asyncio.create_task(fetch(session, url)) for url in url_list]await asyncio.wait(tasks)if __name__ == '__main__':asyncio.run(main())
结果发送请求: https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg发送请求: https://www2.autoimg.cn/newsdfs/g30/M01/3C/E2/120x90_0_autohomecar__ChcCSV2BBICAUntfAADjJFd6800429.jpg发送请求: https://www3.autoimg.cn/newsdfs/g26/M0B/3C/65/120x90_0_autohomecar__ChcCP12BFCmAIO83AAGq7vK0sGY193.jpg下载完成 https://www2.autoimg.cn/newsdfs/g30/M01/3C/E2/120x90_0_autohomecar__ChcCSV2BBICAUntfAADjJFd6800429.jpg下载完成 https://www3.autoimg.cn/newsdfs/g26/M0B/3C/65/120x90_0_autohomecar__ChcCP12BFCmAIO83AAGq7vK0sGY193.jpg下载完成 https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg
上述两种的执行对比之后会发现,基于协程的异步编程 要比 同步编程的效率高了很多。因为:
- 同步编程,按照顺序逐一排队执行,如果图片下载时间为2分钟,那么全部执行完则需要6分钟。
- 异步编程,几乎同时发出了3个下载任务的请求(遇到IO请求自动切换去发送其他任务请求),如果图片下载时间为2分钟,那么全部执行完毕也大概需要2分钟左右就可以了。
小结 协程一般应用在有IO操作的程序中,因为协程可以利用IO等待的时间去执行一些其他的代码,从而提升代码执行效率。
以上就是Python协程的方式实现及意义笔记分享的详细内容,更多关于Python协程的方式实现及意义的资料请关注脚本之家其它相关文章!
推荐阅读
- 关于QueryWrapper|关于QueryWrapper,实现MybatisPlus多表关联查询方式
- mybatisplus|mybatisplus where QueryWrapper加括号嵌套查询方式
- python学习之|python学习之 实现QQ自动发送消息
- 逻辑回归的理解与python示例
- python自定义封装带颜色的logging模块
- 【Leetcode/Python】001-Two|【Leetcode/Python】001-Two Sum
- Python基础|Python基础 - 练习1
- Python爬虫|Python爬虫 --- 1.4 正则表达式(re库)
- 使用协程爬取网页,计算网页数据大小
- Python(pathlib模块)