我开始使用cProfile来分析我的python脚本。
我注意到了一些很奇怪的东西。

当我使用time来衡量脚本的运行时间时,它需要4.3秒。

当我使用python -m cProfile script.py时,需要7.3秒。

在代码中运行探查器时:

import profile
profile.run('main()')

需要63秒!!

我可以理解为什么添加分析时可能要花更多时间,但是为什么从外部使用cProfile或将其作为代码的一部分有如此大的区别呢?
使用profile.run会花费很多时间吗?

最佳答案

奇怪的是,您看到的是预期的行为。在python文档的introduction to the profilers部分中,它指出profilecProfile相比,增加了“显着的配置文件程序开销”。您所看到的区别在于所使用的库,而不是如何调用它们。考虑以下脚本:

import profile
import cProfile

def nothing():
    return

def main():
    for i in xrange(1000):
        for j in xrange(1000):
            nothing()

    return

cProfile.run('main()')
profile.run('main()')
cProfile的输出显示main运行大约需要0.143秒,而profile变体报告为1.645秒,这是〜11.5倍的时间。

现在,让我们再次将脚本更改为此:
def nothing():
    return

def main():
    for i in xrange(1000):
        for j in xrange(1000):
            nothing()

    return

if __name__ == "__main__":
    main()

并与探查器一起调用它:



报告主电源运行1.662秒。



报告主电源运行0.143秒。

这表明启动分析器的方式与cProfileprofile之间的差异无关。差异是由两个探查器处理“事件”(例如函数调用或返回)的方式引起的。在这两种情况下,整个执行代码中都有软件 Hook ,这些 Hook 会触发回调以跟踪这些事件,并执行诸如更新事件计数器和启动或停止计时器之类的操作。但是,profile模块在Python中 native 处理所有这些事件,这意味着您的解释器必须离开您的代码,执行回调操作,然后返回以继续执行您的代码。
cProfile必须执行相同的操作(执行概要分析回调),但是由于回调是用C编写的,因此速度要快得多。看看这两个模块文件 profile.py cProfile.py 展示了一些区别:
  • profile.py 是610行,而 cProfile.py 只有199行-大部分功能都在C语言中处理。
  • profile.py 主要利用Python库,而 cProfile.py 则导入C代码文件“_lsprof”。可以在here上查看源代码。
  • profile.py 中的Profile类不继承任何其他类(第111行),而 cProfile.py (第66行)中的Profile类继承自_lsprof.Profiler,该实现在C源文件中实现。

  • 正如文档所述,cProfile通常是要使用的方式,仅因为它主要是用C实现的,所以一切都更快。

    顺便说一句,您可以通过对其进行校准来提高profile的性能。有关如何执行此操作的详细信息,请参见available in the docs。有关详细信息,请参见Deterministic Profilinglimitations的Python文档部分中有关如何/为什么使用所有这些内容的方式。

    TL; DR
    cProfile更快,因为顾名思义,它大多数是在C中实现的。这与profile模块形成对比,后者必须处理 native Python中的所有性能分析回调。从命令行调用概要分析器还是在脚本内部手动调用概要文件对两个模块之间的时间差没有影响。

    10-08 09:45