奇怪的是,你看到的是预期的行为。在Python 文档的分析器部分的介绍中,它指出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()')
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.py和cProfile.py显示了一些差异:
- profile.py是 610 行,而cProfile.py只有 199 行——它的大部分功能都在 C 中处理。
- profile.py主要使用 Python 库,而cProfile.py导入“_lsprof”,一个 C 代码文件。来源可以在这里查看。
- profile.py中的
Profile
类不继承自任何其他类(第 111 行),而cProfile.py中的类(第 66 行)继承自C 源文件中实现的 .Profile
_lsprof.Profiler
正如文档所述,cProfile
通常是要走的路,仅仅是因为它主要是用 C 实现的,所以一切都更快。
顺便说一句,您可以profile
通过校准它来提高性能。文档中提供了有关如何执行此操作的详细信息。有关如何/为什么所有这些内容的详细信息,请参见 Python 文档的Deterministic Profiling和限制部分。
TL;博士
cProfile
速度要快得多,因为正如它的名字所暗示的那样,它的大部分是用 C 实现的。这与profile
模块相反,它必须处理本机 Python 中的所有分析回调。无论您是从命令行调用分析器还是在脚本中手动调用分析器,都不会影响两个模块之间的时间差。