Python cProfile中的严重开销?

Python cProfile中的严重开销?,python,performance,time,profile,cprofile,Python,Performance,Time,Profile,Cprofile,大家好,蟒蛇专家们,我开始使用cProfile,以便对我的程序有更详细的计时信息。然而,这是相当令人不安的,我有一个显着的开销。你知道为什么cProfile报告7秒,而时间模块在下面的代码中只报告2秒吗 # a simple function def f(a, b): c = a+b # a simple loop def loop(): for i in xrange(10000000): f(1,2) # timing using time module # 2 seconds

大家好,蟒蛇专家们,我开始使用cProfile,以便对我的程序有更详细的计时信息。然而,这是相当令人不安的,我有一个显着的开销。你知道为什么cProfile报告7秒,而时间模块在下面的代码中只报告2秒吗

# a simple function

def f(a, b):
 c = a+b

# a simple loop
def loop():
 for i in xrange(10000000):
  f(1,2)

# timing using time module
# 2 seconds on my computer
from time import time
x = time()
loop()
y = time()
print 'Time taken %.3f s.' % (y-x)

# timing using cProfile
# 7 seconds on my computer
import cProfile
cProfile.runctx('loop()', globals(), locals())

因为它要做更多的工作<代码>时间只是对整个操作进行计时,而
cProfile
则在检测下运行它,以便获得详细的细分。显然,评测并不用于生产,因此2.5倍的开销似乎是一个很小的代价。

函数
f
返回得非常快。使用cProfile时,一次调用
f
的时间不准确,因为时间太小,与测量时间的误差相当。用于测量时间差的时钟只能精确到0.001s。因此,每次测量的误差可能比您试图测量的时间大几个数量级。这样做7次,你就会得到虚假的结果。(有关这方面的更多讨论,请参阅。)

请注意,如果将代码更改为使用

def f(a, b):
 for i in xrange(int(1e4)):    
     c = a+b

# a simple loop
def loop():
 for i in xrange(int(1e3)):
  f(1,2)
你得到

Time taken 0.732 s.
         1003 function calls in 0.725 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.725    0.725 <string>:1(<module>)
     1000    0.723    0.001    0.723    0.001 test.py:4(f)
        1    0.001    0.001    0.725    0.725 test.py:9(loop)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
所用时间为0.732秒。
在0.725 CPU秒内调用1003个函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1    0.000    0.000    0.725    0.725 :1()
1000 0.723 0.001 0.723 0.001试验。py:4(f)
1 0.001 0.001 0.725 0.725测试。py:9(回路)
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}

您正在执行相同数量的循环,但是每次调用
f
都需要更长的时间。这减少了每次测量的误差。(每次调用
f
的时间都包含一个错误,该错误现在没有测量到的总时间大。)

此外,该函数非常简单,从相对而言,探查器似乎占用了大量的总运行时间。感谢您的回复。如果我将loop()中的迭代次数从1000万次增加到1亿次,则计时将线性扩展!时间模块用了20秒,cProfile用了70秒。我不介意cProfile是否需要更长的运行时间,但是报告的时间(即在代码中花费的实际时间)应该排除开销。有没有办法校准cProfile(因为我只对代码中实际花费的时间感兴趣)?@xqx:我不知道。评测可以让您了解程序不同部分的相对性能,但它不适用于生产性能报告。谢谢Owen。我不确定我们能在多大程度上依赖python分析器给出的相对性能数字,因为开销成本不能保证均匀分布。有没有可能某些函数的开销很大(比如说10倍),而其他函数的开销很小,从而导致结果失真。我不确定评测包是如何实现的,所以我不知道哪些因素会增加开销。子函数调用的数量无疑是一个因素,正如下面unutbu的回复所解释的。嗨unutbu。在您的示例中,使用和不使用探查器所花费的时间非常接近,即0.732s和0.725s。除了您提到的可能引入的错误之外,我认为在我的示例中,函数f被调用的次数更多(在您的示例中是1e7而不是1e3),因此具有更高的分析成本。