noo*_*omz 71 python unix shell benchmarking
通常我使用shell命令time.我的目的是测试数据是小型,中型,大型还是非常大的集合,多少时间和内存使用量.
用于linux或python的任何工具都可以做到这一点?
exh*_*uma 100
看一下timeit,python profiler和pycallgraph.
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"))
Run Code Online (Sandbox Code Playgroud)
本质上,您可以将python代码作为字符串参数传递,它将以指定的次数运行并打印执行时间.来自文档的重要部分:
timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)
Timer使用给定语句,设置 代码和 计时器函数创建实例,并timeit使用数字执行运行其方法 .
......和:
Timer.timeit(number=1000000)主要陈述的时间编号执行.这将执行一次setup语句,然后返回执行主语句多次所需的时间,以秒为单位测量为浮点数.参数是通过循环的次数,默认为一百万.要使用的主语句,setup语句和timer函数将传递给构造函数.
注意
默认情况下,在计时期间
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")')
Run Code Online (Sandbox Code Playgroud)
哪个会给你:
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)
Run Code Online (Sandbox Code Playgroud)
这两个模块都应该让您了解在哪里寻找瓶颈.
另外,为了掌握输出profile,请看看这篇文章
此模块使用graphviz创建如下所示的调用图:

您可以通过颜色轻松查看哪些路径用尽了最多的时间.您可以使用pycallgraph API或使用打包的脚本创建它们:
pycallgraph graphviz -- ./mypythonscript.py
Run Code Online (Sandbox Code Playgroud)
但开销相当可观.因此,对于已经长时间运行的流程,创建图表可能需要一些时间.
Dan*_*Liu 26
我使用一个简单的装饰器为func计时
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
Run Code Online (Sandbox Code Playgroud)
Sam*_*ins 13
该timeit模块是缓慢的,怪异的,所以我写了这一点:
def timereps(reps, func):
from time import time
start = time()
for i in range(0, reps):
func()
end = time()
return (end - start) / reps
Run Code Online (Sandbox Code Playgroud)
例:
import os
listdir_time = timereps(10000, lambda: os.listdir('/'))
print "python can do %d os.listdir('/') per second" % (1 / listdir_time)
Run Code Online (Sandbox Code Playgroud)
对我来说,它说:
python can do 40925 os.listdir('/') per second
Run Code Online (Sandbox Code Playgroud)
这是一种原始的基准测试,但它已经足够好了.
Mar*_*ing 10
我通常会快速time ./script.py查看需要多长时间.但这并没有向你显示内存,至少不是默认值.您可以使用/usr/bin/time -v ./script.py获取大量信息,包括内存使用情况.
pip install line_profiler
Run Code Online (Sandbox Code Playgroud)
@profile在函数之前添加一个装饰器。例如:pip install line_profiler
Run Code Online (Sandbox Code Playgroud)
kernprof -l <file_name>创建 line_profiler 的实例。例如:kernprof -l test.py
Run Code Online (Sandbox Code Playgroud)
kernprof 将打印Wrote profile results to <file_name>.lprof成功。例如:
Wrote profile results to test.py.lprof
Run Code Online (Sandbox Code Playgroud)
python -m line_profiler <file_name>.lprof打印基准测试结果。例如:python -m line_profiler test.py.lprof
Run Code Online (Sandbox Code Playgroud)
您将看到每行代码的详细信息:
Timer unit: 1e-06 s
Total time: 0.0021632 s
File: test.py
Function: function at line 1
Line # Hits Time Per Hit % Time Line Contents
==============================================================
1 @profile
2 def function(base, index, shift):
3 1000 796.4 0.8 36.8 addend = index << shift
4 1000 745.9 0.7 34.5 result = base + addend
5 1000 620.9 0.6 28.7 return result
Run Code Online (Sandbox Code Playgroud)
pip install memory_profiler
Run Code Online (Sandbox Code Playgroud)
@profile在函数之前添加一个装饰器。例如:@profile
def function(base, index, shift):
addend = index << shift
result = base + addend
return result
Run Code Online (Sandbox Code Playgroud)
python -m memory_profiler <file_name>打印基准测试结果。例如:python -m memory_profiler test.py
Run Code Online (Sandbox Code Playgroud)
您将看到每行代码的详细信息:
Filename: test.py
Line # Mem usage Increment Occurences Line Contents
============================================================
1 40.246 MiB 40.246 MiB 1 @profile
2 def function():
3 40.246 MiB 0.000 MiB 1 result = []
4 40.758 MiB 0.008 MiB 10001 for i in range(10000):
5 40.758 MiB 0.504 MiB 10000 result.append(i)
6 40.758 MiB 0.000 MiB 1 return result
Run Code Online (Sandbox Code Playgroud)
多次调用函数以尽量减少对环境的影响。
snakevizcProfile 的交互式查看器
https://github.com/jiffyclub/snakeviz/
/sf/answers/111512411/中提到了 cProfile ,评论中提到了 Snakeviz,但我想进一步强调它。
仅通过查看cprofile/pstats输出来调试程序性能是非常困难的,因为它们只能开箱即用地计算每个函数的总时间。
然而,我们真正需要的是查看包含每个调用的堆栈跟踪的嵌套视图,以便轻松找到主要瓶颈。
这正是 Snakeviz 通过其默认的“冰柱”视图提供的功能。
首先,您必须将 cProfile 数据转储到二进制文件,然后您可以对其进行蛇形可视化
pip install -u snakeviz
python -m cProfile -o results.prof myscript.py
snakeviz results.prof
Run Code Online (Sandbox Code Playgroud)
这将打印一个指向 stdout 的 URL,您可以在浏览器上打开该 URL,其中包含所需的输出,如下所示:
然后你可以:
更多面向分析的问题:如何分析 Python 脚本?
内存分析器满足您的所有内存需求。
https://pypi.python.org/pypi/memory_profiler
运行 pip 安装:
pip install memory_profiler
Run Code Online (Sandbox Code Playgroud)
导入库:
import memory_profiler
Run Code Online (Sandbox Code Playgroud)
为您要分析的项目添加装饰器:
@profile
def my_func():
a = [1] * (10 ** 6)
b = [2] * (2 * 10 ** 7)
del b
return a
if __name__ == '__main__':
my_func()
Run Code Online (Sandbox Code Playgroud)
执行代码:
python -m memory_profiler example.py
Run Code Online (Sandbox Code Playgroud)
接收输出:
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
Run Code Online (Sandbox Code Playgroud)
示例来自上面链接的文档。
如果您不想为 timeit 编写样板代码并轻松分析结果,请查看benchmarkit。它还保存了以前运行的历史记录,因此可以轻松地在开发过程中比较相同的功能。
# 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',
)
Run Code Online (Sandbox Code Playgroud)
打印到终端并返回包含上次运行数据的字典列表。命令行入口点也可用。
如果您更改N=1000000并重新运行