热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

7个测量Python脚本和控制内存以及CPU使用率的技巧

本文的作者是MarinaMele,原文地址是7tipstoTimePythonscriptsandcontrolMemory&CPUusage当运行一个复杂的Python程序,它需

本文的作者是 Marina Mele,原文地址是 7 tips to Time Python scripts and control Memory & CPU usage

当运行一个复杂的 Python 程序,它需要很长时间来执行。你或许想提升它的执行时间。但如何做?

首先,你需要工具来查明你代码的瓶颈,比如,那部分执行花费的时间长。用这个方法,你可以首先专注于提升这部分的速度。

而且,你也应该控制内存和 CPU 使用率,因为它可以为你指出的代码可以改进的新的部分。

所以,在本文中,我将对 7 个不同的 Python 工具发表意见,给你一些关于你函数执行时间和内存以及 CPU 使用率的见解。

1. 使用一个装饰器来测量你的函数

测量一个函数最简单的方式就是定义一个装饰器来测量运行该函数的运行时间,并打印该结果:

import time
from functools import wraps
def fn_timer(function):
@wraps(function)
def function_timer(*args, **kwargs):
t0 = time.time()
result = function(*args, **kwargs)
t1 = time.time()
print ("Total time running %s: %s seconds" %
(function.func_name, str(t1-t0))
)
return result
return function_timer

这时,你已经在你想测量的函数之前添加了装饰器,像:

@fn_timer
def myfunction(...):
...

例如,让我们测量下排序一个 2000000 个随机数的数组会花费多长时间:

@fn_timer
def random_sort(n):
return sorted([random.random() for i in range(n)])
if __name__ == "__main__":
random_sort(2000000)

如果你运行你的脚本,你将看到:

Total time running random_sort: 1.41124916077 seconds

2. 使用 timeit 模块

另外一个选项是使用 timeit 模块,它给你测量一个平均时间。

为了运行它,在你的终端执行以下命令:

$ python -m timeit -n 4 -r 5 -s "import timing_functions" "timing_functions.random_sort(2000000)"

timing_functions 是你脚本的名字。

在输出的最后,你会看到一些像这样的东西:

4 loops, best of 5: 2.08 sec per loop

表明了运行这个测试 4 次(-n 4),并在每个测试中重复平均 5 次(-r 5),最佳的结果是 2.08 秒。

如果你没有指定测试或者重复,它默认是 10 次循环和 5 次重复。

3. 使用 Uinx 的 time 命令

尽管如此,装饰器和 timeit 模块都是基于 Python 的。这就是为什么 unix time 工具或许有用,因为它是一个外部的 Python 测量。

为了运行 time 工具类型:

$ time -p python timing_functions.py

将给出如下输出:

Total time running random_sort: 1.3931210041 seconds
real 1.49
user 1.40
sys 0.08

第一行来自于我们定义的装饰器,其他三行是:

  • real 表明了执行脚本花费的总时间
  • User 表明了执行脚本花费在的 CPU 时间
  • Sys 表明了执行脚本花费在内核函数的时间

因此, real time 和 user+sys 相加的不同或许表明了时间花费在等待 I/O 或者是系统在忙于执行其他任务。

4. 使用 cProfile 模块

如果你想知道花费在每个函数和方法上的时间,以及它们被调用了多少次,你可以使用 cProfile 模块。

$ python -m cProfile -s cumulative timing_functions.py

现在你将看到你的代码中每个函数被调用多少次的详细描述,并且它将通过累积花费在每个函数上面的时间来排序(感谢 -s cumulative 选项)

《7 个测量 Python 脚本和控制内存以及 CPU 使用率的技巧》

你将看到花费在运行你的脚本的总时间是比以前高的。这是我们测量每个函数执行时间的损失。

5. 使用 line_profiler 模块

line_profiler 给出了在你代码每一行花费的 CPU 时间。

这个模块首先应该被安装,使用命令:

$ pip install line_profiler

下一步,你需要指定你想使用装饰器 @profile 评估哪个函数(你不需要把它 import 到你的文件中)。

@profile
def random_sort2(n):
l = [random.random() for i in range(n)]
l.sort()
return l
if __name__ == "__main__":
random_sort2(2000000)

最后,你可以通过键入以下命令取得 random_sort2 函数逐行的描述:

$ kernprof -l -v timing_functions.py

-l 标识表明了逐行和 -v 标识表明详细输出。使用这个方法,我们看到了数组结构花费了 44% 的计算时间,sort() 方法花费了剩余的 56%。

《7 个测量 Python 脚本和控制内存以及 CPU 使用率的技巧》

你也将看到,由于时间测量,这个脚本执行花费的或许更长。

6. 使用 memory_profiler 模块

memory_profiler 模块被用于在逐行的基础上,测量你代码的内存使用率。尽管如此,它可能使得你的代码运行的更慢。

安装:

$ pip install memory_profiler

也建议安装 psutil 包,使得 memory_profile 模块运行的更快:

$ pip install psutil

类似 line_profiler 的方式,使用装饰器 @profile 来标记哪个函数被跟踪。下一步,键入:

$ python -m memory_profiler timing_functions.py

是的,前面的脚本比之前的 1 或 2 秒需要更长的时间。并且,如果你不安装 psutil 模块,你将一直等待结果。

《7 个测量 Python 脚本和控制内存以及 CPU 使用率的技巧》

看上面的输出,注意内存使用率的单位是 MiB,这代表的是兆字节(1MiB = 1.05MB)。

7. 使用 guppy 包

最后,使用这个包,你可以跟踪每个类型在你代码中每个阶段(字符, 元组, 字典 等等)有多少对象被创建了。

安装:

$ pip install guppy

下一步,像这样添加到你的代码中:

from guppy import hpy
def random_sort3(n):
hp = hpy()
print "Heap at the beginning of the function\n", hp.heap()
l = [random.random() for i in range(n)]
l.sort()
print "Heap at the end of the function\n", hp.heap()
return l
if __name__ == "__main__":
random_sort3(2000000)

并且这样运行你的代码:

$ python timing_functions.py

你将看到一些像下面的输出:

《7 个测量 Python 脚本和控制内存以及 CPU 使用率的技巧》

通过配置 heap 在你的代码的不同地方,你可以在脚本中学到对象的创建和销毁。

如果你想学习更多提升你 Python 代码的知识,我建议你看看 2014 年 11 月出版的 High Performance Python: Practical Performant Programming for Humans 这本书。


推荐阅读
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 很多时候在注册一些比较重要的帐号,或者使用一些比较重要的接口的时候,需要使用到随机字符串,为了方便,我们设计这个脚本需要注意 ... [详细]
  • Python中程序员的面试题有哪些
    小编给大家分享一下Python中程序员的面试题有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有 ... [详细]
  • 数据结构与算法习题replacementselectionsort(置换选择排序)TimeLimit:1000msMemoryLimit:65536kBDescrip ... [详细]
  • 【原创】利用Python进行河流遥感处理的PyRIS软件开发
    今天开始着手改造pyris1.0.文章地址:https:doi.org10.1016J.ENVSOFT.2018.03.028Monegaglia,2 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Python已成为全球最受欢迎的编程语言之一,然而Python程序的安全运行存在一定的风险。本文介绍了Python程序安全运行需要满足的三个条件,即系统路径上的每个条目都处于安全的位置、"主脚本"所在的目录始终位于系统路径中、若python命令使用-c和-m选项,调用程序的目录也必须是安全的。同时,文章还提出了一些预防措施,如避免将下载文件夹作为当前工作目录、使用pip所在路径而不是直接使用python命令等。对于初学Python的读者来说,这些内容将有所帮助。 ... [详细]
  • 生产环境下JVM调优参数的设置实例
     正文前先来一波福利推荐: 福利一:百万年薪架构师视频,该视频可以学到很多东西,是本人花钱买的VIP课程,学习消化了一年,为了支持一下女朋友公众号也方便大家学习,共享给大家。福利二 ... [详细]
  • 开发笔记:快速排序和堆排序
    本文由编程笔记#小编为大家整理,主要介绍了快速排序和堆排序相关的知识,希望对你有一定的参考价值。快速排序思想:在partition中,首先以最右边的值作为划分值x,分别维护小于 ... [详细]
author-avatar
白云飞羽_389
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有