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

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


当前回答

只有终端(也是最简单的)解决方案,以防所有这些花哨的UI无法安装或运行:完全忽略cProfile并将其替换为pyinstrument,它将在执行后立即收集并显示调用树。

安装:

$ pip install pyinstrument

配置文件和显示结果:

$ python -m pyinstrument ./prog.py

适用于蟒蛇2和3。

[编辑]这里可以找到API的文档,用于分析代码的一部分。

其他回答

这取决于您希望从分析中看到什么。简单的时间度量可以由(bash)给出。

time python python_prog.py

甚至“/usr/bin/time”也可以使用“--verbose”标志输出详细的度量。

为了检查每个函数给出的时间度量,并更好地了解在函数上花费的时间,可以使用python中的内置cProfile。

进入更详细的指标,如绩效,时间不是唯一的指标。您可以担心内存、线程等问题。分析选项:line_profiler是另一个通常用于逐行查找定时度量的分析器。2.memory_profiler是一个评测内存使用情况的工具。3.heapy(来自项目Guppy)描述如何使用堆中的对象。

这些是我常用的一些。但如果你想了解更多,试试看这本书这是一本非常好的书,讲述了如何从性能出发。您可以转到使用Cython和JIT(实时)编译的python的高级主题。

值得指出的是,使用探查器仅在主线程上有效(默认情况下),如果使用它们,您将无法从其他线程获得任何信息。这可能有点棘手,因为探查器文档中完全没有提到它。

如果您还想评测线程,那么您需要查看文档中的threading.setprofile()函数。

您也可以创建自己的线程.Thread子类:

class ProfiledThread(threading.Thread):
    # Overrides threading.Thread.run()
    def run(self):
        profiler = cProfile.Profile()
        try:
            return profiler.runcall(threading.Thread.run, self)
        finally:
            profiler.dump_stats('myprofile-%d.profile' % (self.ident,))

并使用ProfiledThread类而不是标准类。它可能会给你更多的灵活性,但我不确定它是否值得,特别是如果你使用的是不使用你的类的第三方代码。

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

只有终端(也是最简单的)解决方案,以防所有这些花哨的UI无法安装或运行:完全忽略cProfile并将其替换为pyinstrument,它将在执行后立即收集并显示调用树。

安装:

$ pip install pyinstrument

配置文件和显示结果:

$ python -m pyinstrument ./prog.py

适用于蟒蛇2和3。

[编辑]这里可以找到API的文档,用于分析代码的一部分。

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。