用python做的实用小脚本 跑一个小脚本,要吃多少内存

在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
标签:至少1个,最多5个
本文的作者是 ,原文地址是
当运行一个复杂的 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
这时,你已经在你想测量的函数之前添加了装饰器,像:
def myfunction(...):
例如,让我们测量下排序一个 2000000 个随机数的数组会花费多长时间:
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. seconds
2. 使用 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 的
尽管如此,装饰器和 timeit 模块都是基于 Python 的。这就是为什么 unix time 工具或许有用,因为它是一个外部的 Python 测量。
为了运行 time 工具类型:
$ time -p python timing_functions.py
将给出如下输出:
Total time running random_sort: 1. seconds
第一行来自于我们定义的装饰器,其他三行是:
real 表明了执行脚本花费的总时间
User 表明了执行脚本花费在的 CPU 时间
Sys 表明了执行脚本花费在内核函数的时间
因此, real time 和 user+sys 相加的不同或许表明了时间花费在等待 I/O 或者是系统在忙于执行其他任务。
4. 使用 cProfile 模块
如果你想知道花费在每个函数和方法上的时间,以及它们被调用了多少次,你可以使用
$ python -m cProfile -s cumulative timing_functions.py
现在你将看到你的代码中每个函数被调用多少次的详细描述,并且它将通过累积花费在每个函数上面的时间来排序(感谢 -s cumulative 选项)
你将看到花费在运行你的脚本的总时间是比以前高的。这是我们测量每个函数执行时间的损失。
5. 使用 line_profiler 模块
给出了在你代码每一行花费的 CPU 时间。
这个模块首先应该被安装,使用命令:
$ pip install line_profiler
下一步,你需要指定你想使用装饰器 @profile 评估哪个函数(你不需要把它 import 到你的文件中)。
def random_sort2(n):
l = [random.random() for i in range(n)]
if __name__ == "__main__":
random_sort2(2000000)
最后,你可以通过键入以下命令取得 random_sort2 函数逐行的描述:
$ kernprof -l -v timing_functions.py
-l 标识表明了逐行和 -v 标识表明详细输出。使用这个方法,我们看到了数组结构花费了 44% 的计算时间,sort() 方法花费了剩余的
你也将看到,由于时间测量,这个脚本执行花费的或许更长。
6. 使用 memory_profiler 模块
模块被用于在逐行的基础上,测量你代码的内存使用率。尽管如此,它可能使得你的代码运行的更慢。
$ pip install memory_profiler
也建议安装
包,使得 memory_profile 模块运行的更快:
$ pip install psutil
类似 line_profiler 的方式,使用装饰器 @profile 来标记哪个函数被跟踪。下一步,键入:
$ python -m memory_profiler timing_functions.py
是的,前面的脚本比之前的 1 或 2 秒需要更长的时间。并且,如果你不安装 psutil 模块,你将一直等待结果。
看上面的输出,注意内存使用率的单位是 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)]
print "Heap at the end of the function\n", hp.heap()
if __name__ == "__main__":
random_sort3(2000000)
并且这样运行你的代码:
$ python timing_functions.py
你将看到一些像下面的输出:
通过配置 heap 在你的代码的不同地方,你可以在脚本中学到对象的创建和销毁。
如果你想学习更多提升你 Python 代码的知识,我建议你看看 2014 年 11 月出版的
5 收藏&&|&&29
你可能感兴趣的文章
20 收藏,1.7k
21 收藏,3.2k
13 收藏,1.7k
你这些系列性的文章都可以整理收藏夹了!
你这些系列性的文章都可以整理收藏夹了!
分享到微博?
我要该,理由是:
在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。小白刚学python一个星期,但是老师就要求我们使用python写出一个抓取excel表格信息的脚本,还要能够对表格中的数据进行求和
[问题点数:100分,结帖人qingfeng__]
小白刚学python一个星期,但是老师就要求我们使用python写出一个抓取excel表格信息的脚本,还要能够对表格中的数据进行求和
[问题点数:100分,结帖人qingfeng__]
只显示楼主
取消只显示楼主
匿名用户不能发表回复!|管理大量 Python 3 数据分析小脚本的最佳方案是什么? - V2EX
管理大量 Python 3 数据分析小脚本的最佳方案是什么?
12 天前 &locktionc
有一个原始数据库 A,里面包含所有需要的数据。
脚本 1. 从 A 中捞出每天新增的数据,去重后塞入数据库 B
脚本 2:从 A 中捞出每天新增数据,计算与昨日相比的增量并发邮件
脚本 3:从 B 中捞出每天的新增数据,计算与昨日相比的增量并发邮件
脚本 4: 从 B 中捞出所有 tag 为'video'的数据,把它们的 ID 和所有 tag 为'news'的数据进行对比,找出'title'相同的记录
脚本 5:从 B 中捞出数据,查询 Solr,把查询到的数据中的某些字段与 B 中的数据合并,然后写入数据库 C
脚本 6,7,8,9,10,……
例子中主要是数据分析的脚本,在实际中不仅限于此,还有不少 log 分析的脚本,警报脚本等等。
这样的需要定时运行的小脚本有 40 多个。现在全靠 crontab 和 jenkins 运行,已经感觉难以管理了。
对于这些要长不长,要短不短的小脚本,大家有什么比较好的管理方案吗?
支持定时启动
满足某些条件(某个脚本运行完,某个脚本的输出结果满足什么条件等等)启动
热拔插,添加 /修改新脚本不影响老脚本
新脚本可以轻松获取某个或者某些老脚本的输出结果
脚本量大了以后,快速找到实现某个功能的脚本文件以方便排查问题
在 Python 2 时代,有一个 Frabic 可以大致实现这个功能,不知道在 Python 3 时代,有没有更好的方式?
681 次点击所在节点 &
chenqh12 天前这不是写文档的作用吗
locktionc12 天前@ 文档不能解决小脚本的调度和组合的问题。
ToT12 天前公司内部有 scheduler, 可以将任何 job 部署到指定 nodes 运行,可以订制时间+dependency。Python 应该也有类似 lib 吧。
小报告多的话,我是单独写一个 UI 让大家查看的。
bxh56612 天前luigi?
locktionc12 天前@ 我看看
httplife12 天前再写一个 管理 py
locktionc12 天前@ 实在找不到更好的情况下,也只有这样做了。
udumbara12 天前airflow
monsterxx0312 天前用过 luigi, airflow, 这些为了 ETL 做的工具不太适合管理这些脚本,这些工具都需要脚本做适配, 我们的问题是脚本数太多,还是分散到好多人写的,最后框架还是自己写的,给每个脚本写一段 yaml 的配置定义:
daily_log_cal:
type: call
once: per_day
timeout: 600
func: 'path.to.moudule:main'
- '@somebody'
- upstream_job1
每个脚本暴露一个 main 入口函数, 可以从 yaml 中传入参数, 用子进程来运行每个任务,防止一些脚本写的有问题耗内存太多不释放, 用 signal 实现超时控制, 任务运行失败直接 slack 通知到人,
deps 定义一个简单的 DAG 依赖管理, 上游任务失败直接跳过.
还可以根据需求定制一些其他类型的任务,比如 type: sql, 就是制定一个 sql 文件,直接在数据仓库里执行(一般是刷新一些表).
至于运行启动时间, 如果任务有精确到几点几分的要求就单独设置 cronjob,如果只是要求 hourly 或者 daily 运行一次,就定制一个任务 list 作为入口,用 cronjob 触发.
locktionc12 天前@ yaml 对缩进太敏感了。实在要自己写的话,我们可能会用 ini 或者 json
iyaozhen12 天前@ ?哥你都用游标卡尺了。还怕配置文件的缩进。yaml 用作配置文件比 json 和 ini 体验好很多
wibile12 天前airflow
locktionc12 天前@ 我看看
RangerWolf11 天前遇到同样的问题!
没有什么太好的解决方案, 目前也是 crontab 为主。
第 1 页 / 共 1 页&
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到
上打开本讨论主题的完整版本。
是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
is a community of developers, designers and creative people.10种检测Python程序运行时间、CPU和内存占用的方法
转载 & & 作者:Marina Mele
这篇文章主要介绍了10种检测Python程序运行时间、CPU和内存占用的方法,包括利用Python装饰器或是外部的Unix Shell命令等,需要的朋友可以参考下
在运行复杂的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
接着,将这个装饰器添加到需要测量的函数之前,如下所示:
def myfunction(...):
例如,这里检测一个函数排序含有200万个随机数字的数组所需的时间:
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. seconds
2. 使用timeit模块
另一种方法是使用timeit模块,用来计算平均时间消耗。
执行下面的脚本可以运行该模块。
python -m timeit -n 4 -r 5 -s "import timing_functions" "timing_functions.random_sort(2000000)"
这里的timing_functions是Python脚本文件名称。
在输出的末尾,可以看到以下结果:
4 loops, best of 5: 2.08 sec per loop
这表示测试了4次,平均每次测试重复5次,最好的测试结果是2.08秒。
如果不指定测试或重复次数,默认值为10次测试,每次重复5次。
3. 使用Unix系统中的time命令
然而,装饰器和timeit都是基于Python的。在外部环境测试Python时,unix time实用工具就非常有用。
运行time实用工具:
$ time -p python timing_functions.py
输出结果为:
Total time running random_sort: 1. seconds
第一行来自预定义的装饰器,其他三行为:
&&& real表示的是执行脚本的总时间
&&& user表示的是执行脚本消耗的CPU时间。
&&& sys表示的是执行内核函数消耗的时间。
注意:根据,内核是一个计算机程序,用来管理软件的输入输出,并将其翻译成CPU和其他计算机中的电子设备能够执行的数据处理指令。
因此,Real执行时间和User+Sys执行时间的差就是消耗在输入/输出和系统执行其他任务时消耗的时间。
4. 使用cProfile模块
如果想知道每个函数和方法消耗了多少时间,以及这些函数被调用了多少次,可以使用cProfile模块。
$ python -m cProfile -s cumulative timing_functions.py
现在可以看到代码中函数的详细描述,其中含有每个函数调用的次数,由于使用了-s选项(累加),最终结果会根据每个函数的累计执行时间排序。
读者会发现执行脚本所需的总时间比以前要多。这是由于测量每个函数的执行时间这个操作本身也是需要时间。
5. 使用line_profiler模块
line_profiler模块可以给出执行每行代码所需占用的CPU时间。
首先,安装该模块:
$ pip install line_profiler
接着,需要指定用@profile检测哪个函数(不需要在代码中用import导入模块):
def random_sort2(n):
l = [random.random() for i in range(n)]
if __name__ == "__main__":
random_sort2(2000000)
最好,可以通过下面的命令获得关于random_sort2函数的逐行描述。
$ kernprof -l -v timing_functions.py
其中-l表示逐行解释,-v表示表示输出详细结果。通过这种方法,我们看到构建数组消耗了44%的计算时间,而sort()方法消耗了剩余的56%的时间。
同样,由于需要检测执行时间,脚本的执行时间更长了。
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包,也许会更长。
从结果可以看出,内存使用是以MiB为单位衡量的,表示的mebibyte(1MiB = 1.05MB)。
7. 使用guppy包
最后,通过这个包可以知道在代码执行的每个阶段中,每种类型(str、tuple、dict等)分别创建了多少对象。
安装方法如下:
$ pip install guppy
接着,将其添加到代码中:
from guppy import hpy
def random_sort3(n):
hp = hpy()
print "Heap at the beginning of the functionn", hp.heap()
l = [random.random() for i in range(n)]
print "Heap at the end of the functionn", hp.heap()
if __name__ == "__main__":
random_sort3(2000000)
运行代码:
$ python timing_functions.py
可以看到输出结果为:
通过在代码中将heap()放置在不同的位置,可以了解到脚本中的对象创建和删除操作的流程。
如果想学习更多关于Python代码速度优化方面的知识,我建议你去读这本书《.》
希望这篇文章能偶帮到你!^_^
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 python做的实用小脚本 的文章

 

随机推荐