Project Euler和其他编码竞赛通常有最长的运行时间,或者人们吹嘘他们的特定解决方案运行速度有多快。对于Python,有时方法有些笨拙——即向__main__添加计时代码。
描述Python程序运行时间的好方法是什么?
Project Euler和其他编码竞赛通常有最长的运行时间,或者人们吹嘘他们的特定解决方案运行速度有多快。对于Python,有时方法有些笨拙——即向__main__添加计时代码。
描述Python程序运行时间的好方法是什么?
当前回答
添加到https://stackoverflow.com/a/582337/1070617,
我编写了这个模块,允许您使用cProfile并轻松查看其输出。更多信息:https://github.com/ymichael/cprofilev
$ python -m cprofilev /your/python/program
# Go to http://localhost:4000 to view collected statistics.
另请参见:http://ymichael.com/2014/03/08/profiling-python-with-cprofile.html如何理解收集的统计数据。
其他回答
只有终端(也是最简单的)解决方案,以防所有这些花哨的UI无法安装或运行:完全忽略cProfile并将其替换为pyinstrument,它将在执行后立即收集并显示调用树。
安装:
$ pip install pyinstrument
配置文件和显示结果:
$ python -m pyinstrument ./prog.py
适用于蟒蛇2和3。
[编辑]这里可以找到API的文档,用于分析代码的一部分。
我发现cprofiler和其他资源更多地用于优化目的,而不是调试。
我制作了自己的测试模块,用于简单的python脚本速度测试。(在我的例子中,使用ScriptProfilerPy测试了1K+行py文件,并在几分钟内将代码速度提高了10倍。
模块ScriptProfilerPy()将运行代码,并向其添加时间戳。我把模块放在这里:https://github.com/Lucas-BLP/ScriptProfilerPy
Use:
from speed_testpy import ScriptProfilerPy
ScriptProfilerPy("path_to_your_script_to_test.py").Profiler()
输出:
如果你想做一个累积分析器,意思是连续运行函数几次并观察结果的总和。
您可以使用此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():
...
有很多很好的答案,但它们要么使用命令行,要么使用一些外部程序来分析和/或排序结果。
我真的错过了在IDE(eclipsePyDev)中使用而不接触命令行或安装任何东西的方法。所以就在这里。
无命令行分析
def count():
from math import sqrt
for x in range(10**5):
sqrt(x)
if __name__ == '__main__':
import cProfile, pstats
cProfile.run("count()", "{}.profile".format(__file__))
s = pstats.Stats("{}.profile".format(__file__))
s.strip_dirs()
s.sort_stats("time").print_stats(10)
有关更多信息,请参阅文档或其他答案。
对于像austin这样的统计分析器,不需要检测,这意味着您可以简单地使用
austin python3 my_script.py
原始输出不是很有用,但您可以将其传输到flamegraph.pl以获得该数据的火焰图表示,该火焰图提供了时间(以微秒为单位的实时)的细分。
austin python3 my_script.py | flamegraph.pl > my_script_profile.svg
或者,您也可以使用web应用程序Speedscope.app快速可视化收集的样本。如果您安装了pprof,还可以获取austin python(例如,pipx安装austin python)并使用austin2prof转换为pprof格式。
然而,如果您安装了VS Code,您可以使用Austin扩展来获得更交互式的体验,包括源代码热图、顶级函数和收集的调用堆栈
如果您想使用终端,也可以使用TUI,它也具有实时图形模式: