python性能解决_我们如何发现并解决Python代码中性能下降的问题

Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发。

作者:Omer Lachish

最近,我们已经开始使用RQ库代替Celery库作为我们的任务运行引擎。第一阶段,我们只迁移了那些不直接进行查询工作的任务。这些任务包括发送电子邮件,确定哪些查询需要刷新、记录用户事件和其他维护工作。

在部署完成之后我们注意到,任务数量相同的情况下,与Celery库相比,RQ库需要更多的CPU去执行这些任务。我想我应该分享一下我是如何分析和解决这个问题的。

关于Celery库和RQ库的区别

Celery库和RQ库都有工作进程的概念,而且都使用分支来允许多种任务并行运行。当你启动一个Celery工作进程时,它会分到几个不同的进程,每个进程会自主地处理任务。使用RQ库,一个主进程将只会实例化一个子进程(称为“Worker Horse”),该子进程在执行完一个单独的任务后将会结束。当主进程从队列中提取另一项任务时,它将会派出一个新的Work Horse。

在RQ库中,通过使用更多的工作进程,即可实现与Celery相同的并行性。 但是,Celery库和RQ库之间存在着细微的区别:Celery进程在启动时会实例化多个子进程,并将其重用于多个任务。 而使用RQ库时,你必须给每一个任务分配进程。 两种方法都有优点和缺点,但这些内容不在本文讨论范围之内。

标杆分析法

在介绍任何内容之前,我想要确定一个基准,即一个工作容器处理1000项任务需要多长时间。我决定把重心放在record_event工作上,因为它是一种频繁的,轻量级的操作。我使用time命令来衡量性能,这里需要修改一下源代码:为了得出完成1000项任务所需的时间,我倾向于采用RQ库的burst模式,该模式在处理完作业后会退出流程。

我想避免测量那些被安排在基准测试时间段的任务。因此,在task/general.py中的record_event声明上方,通过将@job('default')替换为@job('benchmark'),可以将record_event移至一个名为benchmark的专用队列。

现在我们可以开始计时了。首先,我想查看一个进程启动和停止需要多长时间(没有任何工作)以便之后可以从任何结果中减去该时间:

2bde55c395f544888557636131fc295a.png

在我的计算机上,进程初始化需要14.7秒。我会记住这个时间。

然后,我将1000个虚拟的record_event任务添加进benchmark队列中:

39fe1e45871f473790dce2471070bc89.png

现在,运行相同的命令,看看处理1000项任务需要多长时间:

6a5929bec88e4f31905b93e9377863ac.png

减去14.7秒的启动时间,我们看到4个进程处理1000项任务需要102秒。现在,让我们尝试找出原因!为此,在进程工作的同时,我们将使用py_spy模块。

分析

让我们再增加1000项任务(因为上次的测试已经删除了所有任务),运行进程并同时监控它们所耗费的时间:

3122074069c94f55b69f820a849249bd.png

我知道,最后一条命令非常短。 理想情况下,出于可读性考虑,我会在每个“ &&”上都打断该命令,但是这些命令应该在同一个docker-compose exec worker bash session中按顺序运行。所以,以下是其功能的快速分析:在后台中,burst模式下,开启了4个进程。

等待15秒(大致让它们完成启动。

安装py-spy模块。

运行rq-info命令,并且为其中一个进程进行分层控制。

在该控制过程中记录10秒中的活动情况并将其保存到profile.svg文件中。

结果如下火焰图所示:

557480556f3c4c37b6c5333a55e08ab3.png

从火焰图中,我注意到record_event在sqlalchemy.orm.configure_mappers中花费了很大一部分的执行时间,并且每次处理一项工作时这种情况都会出现。从它们的文档当中,我知道了:初始化到目前为止已构建的所有映射器的映射器间关系。

的确不需要在每一个分支上都发生这种事情。所以,我们可以在主进程当中一次性地初始化这些关系,避免在多个子进程当中重复性这些工作。

因此,在启动进程之前,我已经对sqlalchemy.org.configure_mappers()进行了调用,并再次进行了测试:

f63a095797c04f9d90a23a63cb0f89cd.png

如果我们减去14.7秒的启动时间,4个线程处理1000项任务的时间将从102秒减少到24.6秒。 比以前提高了4倍! 通过修复此程序,我们成功地将RQ生产资源减少了4倍,并保持了相同的吞吐量。

我认为,你应该记住,在单线程和多线程的情况下,应用的行为是有所不同的。如果每一项任务没有繁重的重复的工作要做,通常最好在分到多个线程之前进行一次。这些事情在测试和开发过程中不会出现,因此请确保您进行充分的测试并挖掘出任何会出现的性能问题。英文原文:https://blog.redash.io/how-we-spotted-and-fixed-a-performance-degradation-in-our-python-code/

译者:Lyx

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

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

相关文章

easyui $.parser.parse 页面重新渲染

一些dom元素是动态拼接上的easui的样式,由于页面已经渲染过了,所以需要手动执行渲染某个部件或者整个页面 $.parser.parse(); // parse all the page $.parser.parse(#cc); // parse the specified node $.parser.parse($("#grid").parent());…

Java EE6装饰器:在注入时装饰类

软件中常见的设计模式是装饰器模式 。 我们上一堂课,然后在它周围包装另一堂课。 这样,当我们调用类时,我们总是在到达内部类之前经过周围的类。 Java EE 6允许我们通过CDI创建装饰器,作为其AOP功能的一部分。 如果我们想实现仍然…

C语言代码规范(六)浮点型变量逻辑比较

无论是float还是double类型的变量&#xff0c;都有精度限制。所以一定要避免将浮点变量用""或"!"与数字比较&#xff0c;应该设法转化成为">"或"<"形式。 不建议使用的例子&#xff1a; if(0.0 x) if(0.0 ! x) 强烈推荐的例…

图灵机器人调用数据恢复_机器人也能撩妹?python程序员自制微信机器人,替他俘获女神芳心...

机器人也有感情还记得王传君饰演的《星语心愿之再爱》这部电影吗&#xff1f;王传君饰演的天才程序员“王鹏鹏”因工作原因不能陪伴照顾身在异地的女朋友“林亦男”&#xff0c;呆萌宅男“王鹏鹏”开发出一款以自己为原型的“王鹏鹏8.0”程序去陪伴异地恋的女友&#xff0c;后来…

Spark排错与优化

一. 运维 1. Master挂掉,standby重启也失效 Master默认使用512M内存&#xff0c;当集群中运行的任务特别多时&#xff0c;就会挂掉&#xff0c;原因是master会读取每个task的event log日志去生成spark ui&#xff0c;内存不足自然会OOM&#xff0c;可以在master的运行日志中看到…

在MySQL上使用带密码的GlassFish JDBC安全性

我在该博客上最成功的文章之一是有关在GlassFish上使用基于表单的身份验证来建立JDBC安全领域的文章 。 对这篇文章的一些评论使我意识到&#xff0c;要真正使它安全&#xff0c;应该做的还很多。 开箱即用的安全性 图片&#xff1a; TheKenChan &#xff08; CC BY-NC 2.0 &a…

mgo写入安全机制

mgo写入安全机制 mongo写入安全mgo写入安全mongo写入安全 mongo本身也有一整套的写入安全机制,但是在这篇的内容里只介绍一小部分相关部分.先放一个链接可以跳过本节不看直接看这个 链接. WriteConcern.NONE:没有异常抛出WriteConcern.NORMAL:仅抛出网络错误异常&#xff0c;没…

C学习杂记(二)笔试题:不使用任何中间变量如何将a、b的值进行交换

常见的方法如下 void swap1(int *a, int *b) {int temp *a;*a *b;*b temp; } 不使用中间变量的方法 void swap2(int *a, int *b) {*a *a *b;*b *a - *b;*a *a - *b; } 这种方法是不可取的&#xff0c;因为ab和a-b的运算可能会导致数据溢出。 void swap3(int *a, in…

利用python进行数据分析_利用python进行数据分析复现(1)

&#xfeff;一直以来&#xff0c;都想学习python数据分析相关的知识&#xff0c;总是拖拖拉拉&#xff0c;包括这次这个分享也是。《利用python进行数据分析 第2版》是一次无意之间在简书上看到的一个分享&#xff0c;我决定将很详细。一直都想着可以复现一下。但总有理由&…

在运行时交换出Spring Bean配置

如今&#xff0c;大多数Java开发人员都定期与Spring打交道&#xff0c;而我们当中的许多人已经熟悉了Spring的功能和局限性。 最近&#xff0c;我遇到了一个我从未遇到过的问题&#xff1a;引入了基于运行时引入的配置来重新连接Bean内部的功能。 这对于简单的配置更改或交换掉…

Proximal Algorithms--Accelerated proximal gradient method

4.3 Accelerated proximal gradient method&#xff1a; 加速近端梯度方法&#xff1a; 基本的近端梯度方法的所谓的“加速”版本&#xff0c;就是在算法中包含了一个外推(extrapolation)步骤&#xff0c;一个简单的版本是&#xff1a; yk1:xkωk(xk−xk−1)xk1:proxλkg(yk1−…

C语言代码规范(七)#define

#define 宏定义的使用 #define MAX(x, y) ( ((x) > (y)) ? (x) : (y) ) #define MIN(x, y) ( ((x) < (y)) ? (x) : (y) ) 在宏定义中要把参数用括号扩起来( ((x) > (y)) ? (x) : (y) )。 因为宏只是简单的文本替换&#xff0c;如果不注意&#xff0c;很容…

http 二进制_浅谈HTTP协议

HTTP一、HTTP协议http协议&#xff0c;是超文本传输协议&#xff0c;此协议是基于TCP/IP的协议&#xff0c;是互联网上应用最为广泛的一直网络协议是一种无状态协议&#xff0c;默认端口为80,。设计HTTP的最初目的是为了提供一种发布和接受HTML页面的方法。通过HTTP或者HTTPS协…

登陆注册

登陆注册&#xff0c;注册的账号存在服务器的数据库里&#xff0c;成功了就给你返回成功&#xff0c;失败了就返回失败 有三种登陆方式&#xff1a;普通注册&#xff0c;手机号注册&#xff0c;第三方注册转载于:https://www.cnblogs.com/SensenCoder/p/4885606.html

Java并发教程–线程池

Java 1.5中提供的最通用的并发增强功能之一是引入了可自定义的线程池。 这些线程池使您可以对诸如线程数&#xff0c;线程重用&#xff0c;调度和线程构造之类的东西进行大量控制。 让我们回顾一下。 首先&#xff0c;线程池。 让我们直接进入java.util.concurrent.ExecutorSer…

HTTPPost/AFNetWorking/JSONModel/NSPredicate

一、HTTPPost 1. POST方式发送请求 HTTP协议下默认数据发送请求方法是GET方式&#xff0c;若需要使用POST方法&#xff0c;则需要对发送的请求也就是request对象&#xff0c;进行属性设置。 步骤如下&#xff1a; > 要发送的请求对象&#xff0c;需要使用可变请求对象 [[NSM…

C语言代码规范(八)使用const修饰值不允许改变的变量

使用const限定一个变量的值不允许被改变&#xff0c;从而保护被修饰的东西&#xff0c;防止意外&#xff0c;提高程序的可靠性和安全性。

教育小思

父母的时代是“攒钱&#xff0c;买房&#xff0c;生子&#xff0c;终老”&#xff0c;而现在的时代是“教育&#xff0c;创造&#xff0c;传承&#xff0c;成长”。 改变世界&#xff0c;从教育起步。 传统教育的不足之处&#xff1a; 1. 学习体验不佳&#xff0c;学习者被迫…

linux redis客户端_为什么单线程Redis能那么快?

我们通常说&#xff0c;Redis 是单线程&#xff0c;主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的&#xff0c;这也是 Redis 对外提供键值存储服务的主要流程。但 Redis 的其他功能&#xff0c;比如持久化、异步删除、集群数据同步等&#xff0c;其实是由额外的线…

servlet中文乱码处理

servlet中文乱码处理 如果是post设置req.setCharacterEncoding("utf-8");如果是get&#xff0c;不去修改服务器配置的情况下new String(name.getBytes("iso-8859-1"),"utf-8")数据库乱码?useUnicodetrue&characterEncodingUTF-8转载于:http…