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.mzph.cn/news/835348.shtml

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

相关文章

QT——tableWidget-跳变之舞V1.0-记录学习【1】

QT——tableWidget-跳变之舞V1.0-记录学习【1】 文章目录 QT——tableWidget-跳变之舞V1.0-记录学习【1】前言一、利用QT创建项目文件1.1 完整项目文件如下图所示:1.2 演示: 二、声明文件:2.1 主界面声明文件:mainwindow.h;2.2 控制窗口声明文…

科技查新中医学科研项目查新点如何确立与提炼?案例讲解

一、前言 医学科技查新包括立项查新和成果查新两个部分,其中医学立项查新,它是指在医学科研项目申报开题之前,通过在一定范围内进行该课题的相关文献检索 ( 可以根据项目委托人的具体要求,进行国内检索或者进行国外检索 ) &#x…

区块链(打新)如何被割韭菜

看上去,像我只要去每个都买一遍新发行的代币,一定可以成功的 但是好像没有想象中这么简单,因为这些山寨币,庄家可以自己控盘的,看上去好像有跌宕起伏的买卖,但是一单掀桌子,庄家他自己都不玩了…

Python之数据分析基础

导言: “21世纪的竞争是数据的竞争,谁掌握数据,谁就掌握未来”。如何将大量看似杂乱无章的数据进行聚合,并发现潜在的规律也变得越来越重要。本文将先说明数据分析的步骤,再通过python完成实例数据的处理、分析最终展…

TDM(BPM)-MIMO-FMCW雷达MATLAB仿真

本文通过对车载毫米波雷达信号流程和链路的仿真,建立基本的算法框架,可用于算法性能的验证。并提供基础MATLAB仿真代码,作为分享和参考。 一、信号的产生 车载毫米波雷达广泛使用线性调频连续波雷达,也即发射信号频率随时间线性变…

日本OTC机械手维修需要注意哪些问题呢?

随着工业4.0时代的到来,机器人在制造业中的应用越来越广泛。OTC(Over The Counter)机器人作为工业机器人的一种,以其高效、精准、稳定的特点受到众多企业的青睐。然而,在实际使用过程中,可能会出现一些OTC机…

如何在路由器上做端口映射

假设现在外网有一台ADSL直接拨号上网的电脑,所获得的是公网IP。然后它想访问局域网内的电脑上面的网站,那么就需要在路由器上做端口映射。在路由器上做端口映射的具体规则是:将所有发向自己端口的数据,都转发到内网的计算机。 访…

github删除自己的仓库

测试Github的时候新建了很多仓库,但是后来想删除,找了半天居然没有找到按钮。 我就推测这个删除的功能肯定藏起来了,后来度娘了一下,发现果然在一个比较隐蔽的位置,不知道以后这个功能会不会改到一个比较明显的位置吧…

c++ 归并排序

归并排序是一种遵循分而治之方法的排序算法。它的工作原理是递归地将输入数组划分为较小的子数组并对这些子数组进行排序,然后将它们合并在一起以获得排序后的数组。 简单来说,归并排序的过程就是将数组分成两半,对每一半进行排序&#xff0c…

原子学习笔记5——点亮 LED

一、应用层操控设备的两种方式 应用层如何操控底层硬件,同样也是通过文件 I/O 的方式来实现,设备文件便是各种硬件设备向应用层提供的一个接口,应用层通过对设备文件的 I/O 操作来操控硬件设备,譬如 LCD 显示屏、串口、按键、摄像…

面向对象设计之套路——设计模式

1、总则 面向对象的分析设计编程思想,通过封装、继承、多态把程序的耦合度降低,用设计模式使得程序更加灵活,容易修改,并且易于复用。 让业务逻辑与界面逻辑分开,让它们的耦合度下降,只有分离,…

nginx--FastCGI

CGI 概念 nginx通过与第三方基于协议实现,即通过某种特定协议将客户端请求转发给第三方服务处理,第三方服务器会新建新的进程处理用户的请求,处理完成后返回数据给Nginx并回收进程(下次处理有需要新建),最后nginx在返回给客户端…

Jenkins流水线部署Maven项目

使用Jenkins的流水线功能,构建部署Java Maven项目,步骤很简单但是不少细节需要注意。 一、安装 Jenkins的安装步骤和流程就不具体描述,这里主要介绍一下安装时要注意的几个问题。 1、Jenkins尽量安装最新的几个版本,否则安装完成…

elixir V2测试网验证器一键部署脚本

实际收益 1、服务器环境 服务器系统:centos 7或者ubuntu 20.04(以上) CPU:2核 内存:4G 硬盘:30G ssd 网络:可靠的 100Mbit 互联网 2、部署脚本 #!/bin/bash set -eif [ "$#" -ne 3 ]; thenecho "Usage:

(已解决)org.springframework.amqp.rabbit.support.ListenerExecutionFailedException

报错截图 解决方案 1、登录rabbitMQ网址,删除所有队列 2、重启rabbitMQ 亲测有效!!!亲测有效!!!亲测有效!!!

uni-appH5Android混合开发二 || 使用Android Studio打包应用APK

前言: 在上一章节我们已经讲了如何uni-app离线打包Android平台教程,这一章就该来讲讲如何使用Android Studio打包应用APK提供给Android手机安装使用了。 uni-app跨平台框架介绍和快速入门 uni-app跨平台框架介绍和快速入门 第一步、首先打开已经编译好的…

javac编译web项目中的src

对于单个文件的且不引用其他类文件的java源码用javac编译大家都很熟悉即 javac hello.java, 服务器未安装idea,现在在服务器里面直接编译src目录 1 idea项目结构如下 2 web目录为最终部署的代码 WEB-INF下面没有 classes 目录 3 使用javac 编译src javac -encod…

图:广度优先遍历(BFS)和深度优先遍历(DFS)

1.工具类:队列和字典 export class DictionNary {// 字典的封装constructor() {this.items {}}set(key, value) {// 添加键this.items[key] value}has(key){// 判断键是否存在return this.items.hasOwnProperty(key)}get(key){// 获取键的valuereturn this.has(k…

六级仔细阅读

画两到三个词,精准定位 要原文和同义都满足才选 先看题目,在看原文,不要先看选项 做不出答案就继续往下读,读出来了就不用继续读了 分清楚是问为什么还是是什么,是什么看前面,为什么看后面 不知道就优先…

力扣HOT100 - 215. 数组中第K个最大元素

解题思路: 快速选择,目标是找出数组中第 k 小(或第 k 大)的元素,而不是对整个数组进行排序。 (需要和快排进行区分,快排的目的是排序) 注意: i l - 1, j r 1; 为什…