Python运维之协程

目录

一、定义协程

二、并发

三、异步请求


协程是一种轻量级的线程,它通过保存和恢复寄存器上下文和栈来实现调度切换,从而保留函数执行的状态

这种机制使得协程在处理I/O密集型任务时效率较高,因为它们可以在I/O操作期间让出CPU,以执行其他任务。与多线程相比,协程在同一线程内进行调用,减少了上下文切换的开销。

简而言之,协程通过在函数执行过程中灵活地让出和收回控制权提高了程序的并发性能

一、定义协程

python3.4加入协程的概念,以生成器对象为基础。Python3.5增加了async/await,下面以asyncio为基础介绍协程的使用。

 import asyncioimport time​async def task():print(f"{time.strftime('%H:%M:%S')} task 开始")time.sleep(2)print(f"{time.strftime('%H:%M:%S')} task 结束")​coroutine = task()print(f"{time.strftime('%H:%M:%S')} 产生协程对象 {coroutine},函数并未被调用")loop = asyncio.get_event_loop()print(f"{time.strftime('%H:%M:%S')} 开始调用协程任务")start = time.time()loop.run_until_complete(coroutine)end = time.time()print(f"{time.strftime('%H:%M:%S')} 结束调用协程任务,耗时{end - start} 秒")

提示:首先引入asyncio,主要才可以使用async和await关键字(async定义一个协程await用于临时挂起一个函数或方法的执行),接着使用async定义一个协程方法,然后直接调用该方法,但该方法没有被执行,而是返回一个coroutine协程对象。 使用get_event_loop()方法创建一个事件循环loop,并调用loop对象的run_until_complete()方法协程注册到事件循环loop中,然后启动,这才完成执行。

我们还可以为任务绑定回调函数

 import asyncioimport time​async def task():print(f"{time.strftime('%H:%M:%S')} task 开始")time.sleep(2)print(f"{time.strftime('%H:%M:%S')} task 结束")return "运行结束"​def callback(task):print(f"{time.strftime('%H:%M:%S')} 回调函数开始执行")print(f"状态:{task.result()}")​coroutine = task()print(f"{time.strftime('%H:%M:%S')} 产生协程对象 {coroutine},函数并未被调用")task = asyncio.ensure_future(coroutine)task.add_done_callback(callback)loop = asyncio.get_event_loop()print(f"{time.strftime('%H:%M:%S')} 开始调用协程任务")start = time.time()loop.run_until_complete(task)end = time.time()print(f"{time.strftime('%H:%M:%S')} 结束调用协程任务,耗时{end - start} 秒")

定义了一个协程方法和一个普通方法作为回调函数,回调函数接收一个参数是task对象,asyncio.ensure_future(coroutine)可以返回task对象add_done_callback()为task对象增加一个回调任务。这样我们就定义好了一个coroutine对象和一个回调方法,执行的结果是当couroutine对象执行完毕之后,就去执行声明的callback方法。

二、并发

上述之定义了一个协程任务,如果要多次并尽可能提高效率,可以定义一个task列表,然后使用asyncio的wait()方法执行即可:

 import asyncioimport time​async def task():print(f"{time.strftime('%H:%M:%S')} task 开始")# 异步调用asynico.sleep(1):await asyncio.sleep(2)# time.sleep(2)time.sleep(2)print(f"{time.strftime('%H:%M:%S')} task 结束")return "运行结束"​# 获取EventLoop:loop = asyncio.get_event_loop()# 执行coroutinetasks = [task() for _ in range(5)]start = time.time()loop.run_until_complete(asyncio.wait(tasks))loop.close()end = time.time()print(f"用时{end - start}")

关键字await后面的对象必须是以下类型之一:

  • 一个原生coroutine对象
  • 一个由types.coroutine()修饰的生成器,这个生成器可以返回coroutine对象
  • 一个包含await方法的对象返回的一个迭代器

asyncio.sleep(2)是一个由coroutine修饰的生成器对象,表示等待2秒。

三、异步请求

以常用的网络请求为例,网络请求较多的就是I/O密集型任务。

启动一个简单的Web服务器

 from flask import Flaskimport time​app =  Flask(__name__)​@app.route('/')def index():time.sleep(3)return 'Hello world!'​if __name__ == '__main__':app.run(threaded=True)      # 表明多线程模式启动

如果不开启多线程模式,那么同一时刻遇到多个请求时,只能顺次处理,这样即使我们使用协程异步请求这个服务,也只能一个一个排队。

 import asyncioimport requestsimport time​start = time.time()​async def request():url = 'http://127.0.0.1:5000'print(f'{time.strftime("%H:%M:%S")} 请求 {url}')response = requests.get(url)print(f'{time.strftime("%H:%M:%S")} 得到响应 {response.text}')​tasks = [asyncio.ensure_future(request()) for _ in range(5)]loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))​end = time.time()print(f"耗时{end-start}")

耗时15秒,其实要实现异步处理,必须先有挂起的操作,当一个任务需要等待I/O结果时,可以挂起当前任务,让出CPU的控制权,转去执行其他任务,这样才能充分利用好资源。上述代码串行走,没有实现挂起

要实现异步,使用await将耗时等待的操作挂起让出控制权。当协程执行时遇到await时间循环就会将本协程挂起,转去执行别的协程,直到其他的协程挂起或执行完毕,修改代码:

 import asyncioimport requestsimport time​async def get(url):return requests.get(url)​async def request():url = 'http://127.0.0.1:5000'print(f'{time.strftime("%H:%M:%S")} 请求 {url}')response = await get(url)print(f'{time.strftime("%H:%M:%S")} 得到响应 {response.text}')​start = time.time()tasks = [asyncio.ensure_future(request()) for _ in range(5)]loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))end = time.time()print(f"耗时{end-start}")

上述代码将请求页面的方法封装为一个coroutine读写,在request方法中尝试使用await挂起当前执行的I/O,发现还是15s,原来request不是异步请求,aiohttp是一个支持异步请求的库,将其配合使用即可实现异步请求操作:

 import asyncioimport aiohttpimport time​now = lambda :time.strftime("%H:%M:%S")​async def get(url):async with aiohttp.ClientSession() as session:  # 使用异步上下文管理器response = await session.get(url)result = await response.text()return resultasync def request():url = 'http://127.0.0.1:5000'print(f'{now()} 请求 {url}')result = await get(url)print(f'{now()} 得到响应 {result}')​start = time.time()tasks = [asyncio.ensure_future(request()) for _ in range(5)]loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))end = time.time()print(f"耗时{end-start}")

运行时间只有3秒,扩大20倍还是3秒。可见,异步协程在爬虫项目值速度提升是非常可观了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/326511.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux学习笔记(3)---- Debian测试网速指令及查看是否千兆网卡

测试网速指令 在Debian系统中,测网速的指令主要有以下几种方法: 使用speedtest-cli工具: speedtest-cli是一个常用的网络速度测试工具,可以通过命令行进行安装和运行。首先,需要安装speedtest-cli: sud…

卷积神经网络边缘识别

为什卷积神经网络能够识别图片呢?是基于图片相似度比较,两张图片的点击越大说明两张图片越像,比如我们那狗胡子的图片去比较,如果相似度很高,就是认为这个动物更像狗。点积越大,图片越相似,这个…

2024第八季完美童模 【星光】品牌赛区 【直通】赛 完美收官

2024年5月1日,春风徐徐的【星光品牌赛区】热闹非凡,备受瞩目的第八季完美童模【星光品牌赛区】赛区【直通赛】在这一天正式拉开了帷幕。比赛现场,童模们身着华服,在舞台上演绎了“亚特兰蒂斯”的时尚主题赛。 参赛选手们身着带有海…

Qt---项目的创建及运行

一、创建第一个Qt程序 1. 点击创建项目后,选择项目路径以及给项目起名称 名称:不能有中文、不能有空格 路径:不能有中文路径 2. 默认创建有窗口类myWidget,基类有三种选择:QWidget、QMainWindow、QDialog 3. m…

【Unity Animation 2D】Unity Animation 2D骨骼绑定与动画制作

一、图片格式为png格式,并且角色各部分分离 图片参数设置 需要将Sprite Mode设置为Single,否则图片不能作为一个整体 1、创建骨骼 1.1 旋转Create Bone,点击鼠标左键确定骨骼位置,移动鼠标再次点击鼠标左键确定骨骼&#xff0c…

探秘未来科技:数字化无人巡检的奇妙之旅

嘿,朋友们!下午茶时间到!趁着这会儿咱们来聊一个超级炫酷的话题——数字化无人巡检。想象一下,那些曾经需要人工跋山涉水、风吹日晒的巡检工作,现在正被一群“智能小分队”悄悄接手,是不是觉得既神奇又方便…

三极管 导通条件

一、三极管理解 三极管是电子行业常用的元器件之一,他是一种电流型控制的器件,他有三种工作状态:截止区,放大区、饱和区。当三极管当做开关使用时,他工作在饱和区。下面简短讲解三极管作为开关使用的方法,只…

JSP ssm 智能水表管理myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 JSP ssm 智能水表管理系统是一套完善的web设计系统(系统采用SSM框架进行设计开发,springspringMVCmybatis),对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采…

Electron学习笔记(三)

文章目录 相关笔记笔记说明 五、界面1、获取 webContents 实例(1)通过窗口对象的 webContent 属性获取 webContent 实例:(2)获取当前激活窗口的 webContents 实例:(3)在渲染进程中获…

252 基于MATLAB的自适应差分阈值法检测心电信号的QRS波

基于MATLAB的自适应差分阈值法检测心电信号的QRS波,QRS波群反映左、右心室除极电位和时间的变化,第一个向下的波为Q波,向上的波为R波,接着向下的波是S波。通过GUI进行数据处理,展示心率和QRS。程序已调通,可…

域控安全 ----> Ntds.dit文件抓取

大家还记得内网渗透的初衷吗??? 找到域馆,拿下域控!! 拿下了域控就是拿下了整个域!! 但是大家知道拿下域环境之后应该怎么操作吗(灵魂拷问)??? …

升级! 测试萌新Python学习之连通数据库Pymsql增删改及封装(四)

pymysql 数据库概述python对数据库的增删改查pymysql核心操作事务事务操作pymysql工具类封装每日复习ChatGPT的回答 数据库概述 分类 关系型数据库: 安全 如, mysql oracle SQLite…database tables 行列 非关系型数据库: 高效 如, redis mongoDB…数据存储结构多样 键值对…

字符串函数(一):strcpy(拷贝),strcat(追加),strcmp(比较),及strncpy,strncat,strncmp

字符串函数 一.strcpy(字符串拷贝)1.函数使用2.模拟实现 二.strcat(字符串追加)1.函数使用2.模拟实现 三.strcmp(字符串比较)1.函数使用2.模拟实现 四.strncpy1.函数使用2.模拟实现 五.strncat1.函数使用2.…

汇昌联信电商:拼多多新手怎么做店铺的免费流量会慢慢起来?

在拼多多上开店,新手们往往面临着如何吸引免费流量的挑战。毕竟,流量是店铺生存和发展的血脉,没有流量,就没有销量,店铺也就失去了生命力。那么,作为拼多多新手,如何做才能让店铺的免费流量慢慢…

前端开发者必备:Nginx入门实战宝典,从部署到优化一网打尽

🔥 个人主页:空白诗 文章目录 引言 👋一、Nginx简介 📚二、常见的Web服务器架构 🌀📌 架构概述📌 Nginx的深入探讨 三、正向代理与反向代理 🔮📌 正向代理工作原理&#…

通用型产品发布解决方案(后端环境搭建)

文章目录 后端renren脚手架配置1.解压后放到项目目录下2.新建商品模块1.创建一个新模块 sunliving-commodity2.删除两个不必要的文件3.pom.xml 引入依赖 3.maven进行聚合管理1.将刚才配置的pom.xml文件复制到父项目下并进行修改2.手动将这个pom.xml加入项目(如果右下…

自定义类型——结构体、枚举和联合

自定义类型——结构体、枚举和联合 结构体结构体的声明匿名结构体结构体的自引用结构体的初始化结构体的内存对齐修改默认对齐数结构体传参 位段枚举联合 结构体 结构是一些值的集合,这些值被称为成员变量,结构的每个成员可以是不同类型的变量。 数组是…

【面试经典题】环形链表

个人主页:一代… 个人专栏:数据结构 在面试中我们经常会遇到有关链表的相关题目,面试官通常会对题目给出拓展 下面我就两个leetcode上的一个双指针的题目为例,并对其进行拓展 题目链接:环形链表 题目描述&#xf…

Java抽象类:为何它是你代码架构的基石?

目录 1、抽象类的概念 2、抽象类语法 3、抽象类特性 4、抽象类的作用 5、 完结散花 个人主页:秋风起,再归来~ 文章专栏:javaSE的修炼之路 个人格言:悟已往之不谏,知来者犹可追 克…

人脸消费给传统食堂带来的变化

消费的技术基础是脸部识别,脸部识别是基于人的容貌特征信息进行认证的生物特征识别技术,其突出的特征是以非接触方式进行识别,避免个人信息的泄露。 面部识别和指纹识别、掌纹识别、视网膜识别、骨骼识别、心率识别等都是人体生物特征识别技术…