为什么 python 探查器给出相互矛盾的结果?

Why python profiler gives contradicting results?

玩一下python分析器,看下面的代码:

>>> def testa():
...     a = []
...     pr = cProfile.Profile()
...     pr.enable()
...     for i in range(100000):
...             a.append(1)
...     pr.disable()
...     pr.print_stats()

>>> def testb():
...     a = []
...     pr = cProfile.Profile()
...     pr.enable()
...     for i in range(100000):
...             a = a + [1]
...     pr.disable()
...     pr.print_stats()

基本上我想看看 append 方法与自连接列表之间的结果,我认为自连接会更昂贵,当我调用 testb 实际用了更长时间才完成。

但是探查器的结果是错误的?

>>> testa()
         100002 function calls in 0.006 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
   100000    0.005    0.000    0.005    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.001    0.001    0.001    0.001 {range}


>>> testb()
         2 function calls in 0.001 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.001    0.001    0.001    0.001 {range}

Python 必须每次查找列表的 "append" 方法的含义。语言是非常动态的,方法可以随时改变。要改进这一点,请查找 append 方法一次,然后定期追加:

>>> def testc():
...     a = []
...     pr = cProfile.Profile()
...     pr.enable()
...     list_append = a.append
...     for i in range(100000):
...             list_append(1)
...     pr.disable()
...     pr.print_stats()

您使用的探查器有误。它不会报告从打开到关闭之间经过的时间;它正在收集有关在您打开它和关闭它之间调用的函数的统计信息。 testb 中的大循环没有计时,因为没有函数调用发生。

如果您只是想计时,cProfile 不是合适的工具。我通常会推荐 timeit,但由于 testb 太长了,所以 time.time() 也合适:

def testb():
    start = time.time()
    a = []
    for i in range(100000):
        a = a + [1]
    print time.time() - start