通常我使用shell命令time
。我的目的是测试数据是小数据集,小数据集,大数据集还是非常大的数据集,以及使用多少时间和内存。
有任何适用于linux的工具或仅适用于python的工具吗?
Answers:
看看timeit,python profiler和pycallgraph。还要确保通过nikicc
提及“ SnakeViz ”来查看下面的评论。它为您提供了概要分析数据的另一种可视化效果,可能会有所帮助。
def test():
"""Stupid test function"""
lst = []
for i in range(100):
lst.append(i)
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test"))
# For Python>=3.5 one can also write:
print(timeit.timeit("test()", globals=locals()))
本质上,您可以将它作为字符串参数传递给python代码,它将在指定的时间运行并显示执行时间。文档中的重要内容:
timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)
Timer
使用给定的语句,设置 代码和 计时器函数 创建实例,并timeit
通过数字执行运行其方法 。可选的globals参数指定在其中执行代码的名称空间。
...和:
Timer.timeit(number=1000000)
主语句的 时间编号执行。这将执行一次setup语句,然后返回执行主语句所需的时间(以秒为单位,以浮点数表示)。参数是循环的次数,默认为一百万次。将要使用的主语句,设置语句和计时器函数传递给构造函数。注意: 默认情况下,在计时期间
timeit
暂时关闭garbage collection
。这种方法的优势在于,它使独立计时更具可比性。这个缺点是GC可能是被测功能性能的重要组成部分。如果是这样,则可以将GC作为设置字符串中的第一条语句重新启用。例如:
timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()
分析将使您对发生的事情有更详细的了解。这是官方文档中的“即时示例” :
import cProfile
import re
cProfile.run('re.compile("foo|bar")')
这会给你:
197 function calls (192 primitive calls) in 0.002 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.001 0.001 <string>:1(<module>)
1 0.000 0.000 0.001 0.001 re.py:212(compile)
1 0.000 0.000 0.001 0.001 re.py:268(_compile)
1 0.000 0.000 0.000 0.000 sre_compile.py:172(_compile_charset)
1 0.000 0.000 0.000 0.000 sre_compile.py:201(_optimize_charset)
4 0.000 0.000 0.000 0.000 sre_compile.py:25(_identityfunction)
3/1 0.000 0.000 0.000 0.000 sre_compile.py:33(_compile)
这两个模块都应该使您了解在哪里寻找瓶颈。
另外,要掌握的输出profile
,请看一下这篇文章
该模块使用graphviz创建如下的调用图:
您可以按颜色轻松查看哪些路径消耗最多的时间。您可以使用pycallgraph API或使用打包的脚本来创建它们:
pycallgraph graphviz -- ./mypythonscript.py
开销是相当可观的。因此,对于已经长时间运行的流程,创建图形可能需要一些时间。
我使用一个简单的装饰器来计时功能
def st_time(func):
"""
st decorator to calculate the total time of a func
"""
def st_func(*args, **keyArgs):
t1 = time.time()
r = func(*args, **keyArgs)
t2 = time.time()
print "Function=%s, Time=%s" % (func.__name__, t2 - t1)
return r
return st_func
的 timeit
模块缓慢而奇怪,所以我这样写:
def timereps(reps, func):
from time import time
start = time()
for i in range(0, reps):
func()
end = time()
return (end - start) / reps
例:
import os
listdir_time = timereps(10000, lambda: os.listdir('/'))
print "python can do %d os.listdir('/') per second" % (1 / listdir_time)
对我来说,它说:
python can do 40925 os.listdir('/') per second
这是一种原始的基准测试,但已经足够了。
我通常会快速time ./script.py
查看需要多长时间。但这并没有显示您的内存,至少不是默认情况。您可以/usr/bin/time -v ./script.py
用来获取很多信息,包括内存使用情况。
/usr/bin/time
及其-v
选项在许多发行版中不是默认提供的,必须安装。sudo apt-get install time
在debian,ubuntu等中使用pacman -S time
archlinux
Memory Profiler可满足您所有的内存需求。
https://pypi.python.org/pypi/memory_profiler
运行pip安装:
pip install memory_profiler
导入库:
import memory_profiler
将装饰器添加到要配置的项目中:
@profile
def my_func():
a = [1] * (10 ** 6)
b = [2] * (2 * 10 ** 7)
del b
return a
if __name__ == '__main__':
my_func()
执行代码:
python -m memory_profiler example.py
接收输出:
Line # Mem usage Increment Line Contents
==============================================
3 @profile
4 5.97 MB 0.00 MB def my_func():
5 13.61 MB 7.64 MB a = [1] * (10 ** 6)
6 166.20 MB 152.59 MB b = [2] * (2 * 10 ** 7)
7 13.61 MB -152.59 MB del b
8 13.61 MB 0.00 MB return a
示例来自上面链接的文档。
安装完成后,nose是路径中的脚本,您可以在包含一些python脚本的目录中进行调用:
$: nosetests
这将在当前目录中的所有python文件中查找并执行它可以识别为测试的任何功能:例如,它可以将名称中带有单词test_的任何功能识别为测试。
因此,您可以仅创建一个名为test_yourfunction.py的python脚本,并在其中编写如下代码:
$: cat > test_yourfunction.py
def test_smallinput():
yourfunction(smallinput)
def test_mediuminput():
yourfunction(mediuminput)
def test_largeinput():
yourfunction(largeinput)
那你得跑
$: nosetest --with-profile --profile-stats-file yourstatsprofile.prof testyourfunction.py
并使用以下python行读取配置文件:
python -c "import hotshot.stats ; stats = hotshot.stats.load('yourstatsprofile.prof') ; stats.sort_stats('time', 'calls') ; stats.print_stats(200)"
nose
依靠热点。自Python 2.5起,它不再维护,仅保留用于“特殊用途”
注意timeit
是非常慢的,在我的中型处理器上初始化(或运行该功能)需要12秒钟。您可以测试此可接受的答案
def test():
lst = []
for i in range(100):
lst.append(i)
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test")) # 12 second
为了简单起见,我将使用time
它在我的PC上返回结果0.0
import time
def test():
lst = []
for i in range(100):
lst.append(i)
t1 = time.time()
test()
result = time.time() - t1
print(result) # 0.000000xxxx
snakeviz
cProfile的交互式查看器
https://github.com/jiffyclub/snakeviz/
CPROFILE在提到https://stackoverflow.com/a/1593034/895245和snakeviz在评论中提到,但我想进一步突出它。
仅通过查看就很难调试程序性能 cprofile
/pstats
输出,因为它们只能使每个函数的总时间开箱即用。
但是,我们通常真正需要的是看到一个嵌套视图,其中包含每个调用的堆栈跟踪,以便轻松地实际找到主要瓶颈。
这正是snakeviz通过其默认“ icicle”视图提供的功能。
首先,您必须将cProfile数据转储到二进制文件,然后可以在该文件上使用snakeviz
pip install -u snakeviz
python -m cProfile -o results.prof myscript.py
snakeviz results.prof
这将打印出一个指向stdout的URL,您可以在浏览器中打开该URL,其中包含所需的输出,如下所示:
然后您可以:
面向配置文件的更多问题:如何配置Python脚本?
如果您不希望为timeit编写样板代码,并且不易分析结果,请查看基准测试。此外,它还保存了以前运行的历史记录,因此很容易在开发过程中比较相同的功能。
# pip install benchmarkit
from benchmarkit import benchmark, benchmark_run
N = 10000
seq_list = list(range(N))
seq_set = set(range(N))
SAVE_PATH = '/tmp/benchmark_time.jsonl'
@benchmark(num_iters=100, save_params=True)
def search_in_list(num_items=N):
return num_items - 1 in seq_list
@benchmark(num_iters=100, save_params=True)
def search_in_set(num_items=N):
return num_items - 1 in seq_set
benchmark_results = benchmark_run(
[search_in_list, search_in_set],
SAVE_PATH,
comment='initial benchmark search',
)
打印到终端并返回带有上次运行数据的词典列表。命令行入口点也可用。
如果您更改N=1000000
并重新运行
python -m cProfile -o results.prof myscript.py
。然后,可以通过一个名为SnakeViz的程序在浏览器中很好地呈现oputput文件,该程序使用snakeviz results.prof