Project Euler和其他编码竞赛通常有最长的运行时间,或者人们吹嘘他们的特定解决方案运行速度有多快。对于Python,有时方法有些笨拙——即向__main__添加计时代码。
描述Python程序运行时间的好方法是什么?
Project Euler和其他编码竞赛通常有最长的运行时间,或者人们吹嘘他们的特定解决方案运行速度有多快。对于Python,有时方法有些笨拙——即向__main__添加计时代码。
描述Python程序运行时间的好方法是什么?
当前回答
PyVmMonitor是一种在Python中处理评测的新工具:http://www.pyvmmonitor.com/
它具有一些独特的功能,例如
将探查器附加到正在运行的(CPython)程序Yappi集成的按需分析不同机器上的配置文件多进程支持(多处理、django…)实时采样/CPU视图(带时间范围选择)通过cProfile/配置文件集成进行确定性配置分析现有PStats结果打开DOT文件编程API访问按方法或行对样本进行分组PyDev集成PyCharm集成
注意:它是商业的,但对开源是免费的。
其他回答
Python包括一个名为cProfile的分析器。它不仅给出了总的运行时间,而且还分别计算了每个函数的时间,并告诉每个函数被调用了多少次,从而很容易确定应该在哪里进行优化。
您可以从代码内部或从解释器调用它,如下所示:
import cProfile
cProfile.run('foo()')
更有用的是,您可以在运行脚本时调用cProfile:
python -m cProfile myscript.py
为了更简单,我制作了一个名为“profile.bat”的小批处理文件:
python -m cProfile %1
所以我要做的就是跑:
profile euler048.py
我得到了这个:
1007 function calls in 0.061 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.061 0.061 <string>:1(<module>)
1000 0.051 0.000 0.051 0.000 euler048.py:2(<lambda>)
1 0.005 0.005 0.061 0.061 euler048.py:2(<module>)
1 0.000 0.000 0.061 0.061 {execfile}
1 0.002 0.002 0.053 0.053 {map}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler objects}
1 0.000 0.000 0.000 0.000 {range}
1 0.003 0.003 0.003 0.003 {sum}
编辑:更新了2013年PyCon视频资源的链接,标题为Python评测也可以通过YouTube。
如果你想做一个累积分析器,意思是连续运行函数几次并观察结果的总和。
您可以使用此cumulative_profiler装饰器:
它是python>=3.6特定的,但您可以删除非本地的,因为它可以在旧版本上工作。
import cProfile, pstats
class _ProfileFunc:
def __init__(self, func, sort_stats_by):
self.func = func
self.profile_runs = []
self.sort_stats_by = sort_stats_by
def __call__(self, *args, **kwargs):
pr = cProfile.Profile()
pr.enable() # this is the profiling section
retval = self.func(*args, **kwargs)
pr.disable()
self.profile_runs.append(pr)
ps = pstats.Stats(*self.profile_runs).sort_stats(self.sort_stats_by)
return retval, ps
def cumulative_profiler(amount_of_times, sort_stats_by='time'):
def real_decorator(function):
def wrapper(*args, **kwargs):
nonlocal function, amount_of_times, sort_stats_by # for python 2.x remove this row
profiled_func = _ProfileFunc(function, sort_stats_by)
for i in range(amount_of_times):
retval, ps = profiled_func(*args, **kwargs)
ps.print_stats()
return retval # returns the results of the function
return wrapper
if callable(amount_of_times): # incase you don't want to specify the amount of times
func = amount_of_times # amount_of_times is the function in here
amount_of_times = 5 # the default amount
return real_decorator(func)
return real_decorator
实例
剖析函数baz
import time
@cumulative_profiler
def baz():
time.sleep(1)
time.sleep(2)
return 1
baz()
baz跑了5次并打印了以下内容:
20 function calls in 15.003 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
10 15.003 1.500 15.003 1.500 {built-in method time.sleep}
5 0.000 0.000 15.003 3.001 <ipython-input-9-c89afe010372>:3(baz)
5 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
指定次数
@cumulative_profiler(3)
def baz():
...
cProfile非常适合于分析,而kcachegrind非常适合于可视化结果。中间的pyprov2calltree处理文件转换。
python -m cProfile -o script.profile script.py
pyprof2calltree -i script.profile -o script.calltree
kcachegrind script.calltree
所需的系统包:
kcachegrind(Linux)、qcachegrind(MacOs)
Ubuntu上的设置:
apt-get install kcachegrind
pip install pyprof2calltree
结果:
在研究这个主题时,我遇到了一个叫做SnakeViz的便捷工具。SnakeViz是一个基于web的评测可视化工具。它非常容易安装和使用。我通常使用的方法是用%prun生成一个stat文件,然后在SnakeViz中进行分析。
所使用的主要viz技术是下图所示的Sunburst图表,其中函数调用的层次结构被安排为弧和时间信息的层,以其角度宽度编码。
最好的是你可以与图表互动。例如,要放大,可以单击一个弧,弧及其后代将被放大为新的阳光,以显示更多细节。
当我不是服务器的根用户时,我使用lsprofcalltree.py并像这样运行我的程序:
python lsprofcalltree.py -o callgrind.1 test.py
然后我可以用任何callgrind兼容的软件打开报告,比如qcachegrind