Project Euler和其他编码竞赛通常有最长的运行时间,或者人们吹嘘他们的特定解决方案运行速度有多快。对于Python,有时方法有些笨拙——即向__main__添加计时代码。

描述Python程序运行时间的好方法是什么?


当前回答

在Virtaal的源代码中,有一个非常有用的类和装饰器,它可以使分析(甚至对于特定的方法/函数)非常简单。然后可以在KCacheGrind中非常舒适地查看输出。

其他回答

python wiki是一个用于分析资源的绝佳页面:http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code

python文档也是如此:http://docs.python.org/library/profile.html

如Chris Lawlor所示,cProfile是一个很棒的工具,可以很容易地打印到屏幕上:

python -m cProfile -s time mine.py <args>

或存档:

python -m cProfile -o output.file mine.py <args>

PS>如果您使用的是Ubuntu,请确保安装python配置文件

apt-get install python-profiler 

如果输出到文件,可以使用以下工具获得良好的可视化效果

PyCallGraph:创建调用图图像的工具安装:

 pip install pycallgraph

run:

 pycallgraph mine.py args

视图:

 gimp pycallgraph.png

你可以使用任何你喜欢的方式来查看png文件,我使用了gimp不幸的是,我经常

dot:graph对于cairo渲染器位图太大。缩放0.257079以适合

这使我的图像变得难以使用。所以我通常创建svg文件:

pycallgraph -f svg -o pycallgraph.svg mine.py <args>

PS>确保安装graphviz(提供点程序):

pip install graphviz

使用gprof2dot通过@maxy/@quodlibetor绘制替代图形:

pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg

我发现,如果您不想使用命令行选项,该功能快速且易于使用。

要使用,只需在要分析的每个函数上方添加@profile。

def profile(fnc):
    """
    Profiles any function in following class just by adding @profile above function
    """
    import cProfile, pstats, io
    def inner (*args, **kwargs):
        pr = cProfile.Profile()
        pr.enable()
        retval = fnc (*args, **kwargs)
        pr.disable()
        s = io.StringIO()
        sortby = 'cumulative'   #Ordered
        ps = pstats.Stats(pr,stream=s).strip_dirs().sort_stats(sortby)
        n=10                    #reduced the list to be monitored
        ps.print_stats(n)
        #ps.dump_stats("profile.prof")
        print(s.getvalue())
        return retval
    return inner 

每个函数的输出如下

   Ordered by: cumulative time
   List reduced from 38 to 10 due to restriction <10>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.002    0.002 3151212474.py:37(get_pdf_page_count)
        1    0.000    0.000    0.002    0.002 fitz.py:3604(__init__)
        1    0.001    0.001    0.001    0.001 {built-in method fitz._fitz.new_Document}
        1    0.000    0.000    0.000    0.000 fitz.py:5207(__del__)
        1    0.000    0.000    0.000    0.000 {built-in method fitz._fitz.delete_Document}
        1    0.000    0.000    0.000    0.000 fitz.py:4816(init_doc)
        1    0.000    0.000    0.000    0.000 fitz.py:5197(_reset_page_refs)
        1    0.000    0.000    0.000    0.000 fitz.py:4821(<listcomp>)
       11    0.000    0.000    0.000    0.000 fitz.py:4054(_getMetadata)
        1    0.000    0.000    0.000    0.000 weakref.py:241(values)

根据乔·肖(Joe Shaw)关于多线程代码无法按预期工作的回答,我认为cProfile中的runcall方法只是围绕着已配置的函数调用执行self.enable()和self.disable()调用,因此您可以简单地自己执行,并在对现有代码的干扰最小的情况下使用任何代码。

在研究这个主题时,我遇到了一个叫做SnakeViz的便捷工具。SnakeViz是一个基于web的评测可视化工具。它非常容易安装和使用。我通常使用的方法是用%prun生成一个stat文件,然后在SnakeViz中进行分析。

所使用的主要viz技术是下图所示的Sunburst图表,其中函数调用的层次结构被安排为弧和时间信息的层,以其角度宽度编码。

最好的是你可以与图表互动。例如,要放大,可以单击一个弧,弧及其后代将被放大为新的阳光,以显示更多细节。

有很多很好的答案,但它们要么使用命令行,要么使用一些外部程序来分析和/或排序结果。

我真的错过了在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)

有关更多信息,请参阅文档或其他答案。