我开始使用cProfile
来分析我的python脚本。
我注意到一些非常奇怪的东西。
当我使用time
来衡量脚本的运行时间时,需要4.3秒。
当我使用python -m cProfile script.py
时,需要7.3秒。
在代码中运行探查器时:
import profile
profile.run('main()')
需要63秒!!
我可以理解为什么在添加性能分析时可能需要更多时间,但为什么从外部使用cProfile
或作为代码的一部分之间存在这样的差异?
我使用profile.run
时会花费这么多时间吗?
答案 0 :(得分:6)
奇怪的是,你所看到的是预期的行为。在Python文档的introduction to the profilers部分中,它指出profile
与cProfile
相比,增加了“分析程序的显着开销”。你看到的差异在于你正在使用的库,而不是你如何调用它们。考虑一下这个脚本:
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
的输出显示主要运行约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 profile test_script.py
报告主要运行1.662秒。
python -m cProfile test_script.py
报告主要运行0.143秒。
这表明启动分析器的方式与您在cProfile
和profile
之间看到的差异无关。差异是由两个分析器如何处理“事件”(如函数调用或返回)引起的。在这两种情况下,执行代码中都有软件挂钩,触发回调以跟踪这些事件,并执行更新事件计数器以及启动或停止计时器等操作。但是,profile
模块在Python 中本地处理所有这些事件,这意味着您的解释器必须保留代码,执行回调内容,然后返回继续使用代码。
同样的事情必须发生在cProfile
(执行分析回调),但它更快,因为回调是用C语言编写的。看看两个模块文件 profile.py 和 cProfile.py 演示了一些差异:
Profile
类不会继承任何其他类(第111行),而 cProfile.py中的Profile
类< / strong>(第66行)继承自_lsprof.Profiler
,它在C源文件中实现。正如文档所述,cProfile
通常是要走的路,因为它主要是用C实现的,所以一切都更快。
另外,您可以通过校准来提高profile
的性能。有关如何执行此操作的详细信息,请参阅available in the docs有关如何/为何所有这些内容的详细信息,请参阅Deterministic Profiling和limitations上的Python文档部分。
cProfile
要快得多,因为顾名思义,它的大部分是用C实现的。这与profile
模块形成对比,后者必须处理本机中的所有分析回调。蟒蛇。无论是从命令行调用分析器还是在脚本中手动调用,都不会影响两个模块之间的时差。