6

我开始使用cProfile分析我的 python 脚本。我注意到一些非常奇怪的事情。

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

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

在代码中运行探查器时:

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

需要63秒!!

cProfile我可以理解为什么在添加分析时可能需要更多时间,但是为什么从外部使用或作为代码的一部分使用会有如此大的差异?我使用它需要这么多时间有什么原因profile.run吗?

4

1 回答 1

6

奇怪的是,你看到的是预期的行为。在Python 文档的分析器部分的介绍中,它指出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()')

show main的输出cProfile运行大约需要 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()

并使用探查器调用它:

python -m 配置文件 test_script.py

报告 main 运行 1.662 秒。

python -m cProfile test_script.py

报告 main 运行 0.143 秒。

cProfile这表明您启动分析器的方式与您在和之间看到的差异无关profile。不同之处在于两个分析器如何处理“事件”,例如函数调用或返回。在这两种情况下,执行代码中都有软件挂钩,它们会触发回调以跟踪这些事件并执行诸如更新事件计数器和启动或停止计时器之类的操作。但是,该模块在 Python 中本地profile处理所有这些事件,这意味着您的解释器必须离开您的代码,执行回调内容,然后返回以继续您的代码。

(执行分析回调)也必须发生同样的事情cProfile,但它要快得多,因为回调是用 C 编写的。查看两个模块文件profile.pycProfile.py显示了一些差异:

  1. profile.py是 610 行,而cProfile.py只有 199 行——它的大部分功能都在 C 中处理。
  2. profile.py主要使用 Python 库,而cProfile.py导入“_lsprof”,一个 C 代码文件。来源可以在这里查看。
  3. profile.py中的Profile类不继承自任何其他类(第 111 行),而cProfile.py中的类(第 66 行)继承自C 源文件中实现的 .Profile_lsprof.Profiler

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

顺便说一句,您可以profile通过校准它来提高性能。文档中提供了有关如何执行此操作的详细信息。有关如何/为什么所有这些内容的详细信息,请参见 Python 文档的Deterministic Profiling限制部分。

TL;博士

cProfile速度要快得多,因为正如它的名字所暗示的那样,它的大部分是用 C 实现的。这与profile模块相反,它必须处理本机 Python 中的所有分析回调。无论您是从命令行调用分析器还是在脚本中手动调用分析器,都不会影响两个模块之间的时间差。

于 2014-08-15T21:41:42.060 回答