为啥 python profiler 给出了矛盾的结果?

Posted

技术标签:

【中文标题】为啥 python profiler 给出了矛盾的结果?【英文标题】:Why python profiler gives contradicting results?为什么 python profiler 给出了矛盾的结果? 【发布时间】:2015-07-19 22:44:03 【问题描述】:

玩一下python profiler,看下面的代码:

>>> 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

【问题讨论】:

使用timeit,你会看到很大的不同,a=[];for i in range(100000);a = a + [1] -> 22sa=[];for i in range(100000);a.append(1) -> 7.84ms 【参考方案1】:

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

如果您只是想计时,cProfile 不是可以使用的工具。我通常会推荐timeit,但由于testb 花费的时间非常长,time.time() 也比较合适:

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

【讨论】:

【参考方案2】:

Python 每次都必须查找列表的“追加”方法的含义。语言非常动态,方法可能随时改变。为了改善这一点,查找 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 需要大约 5 秒? @JamesLin:它会发生一次还是每次?我想不出为什么会发生这种情况。 是的,它每次都会发生。

以上是关于为啥 python profiler 给出了矛盾的结果?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 printf() 在 python 中给出一个奇怪的输出?

为啥 GHC 在使用 Coercible 约束时会自相矛盾?

为啥会返回这个矛盾的 clojure.core.logic/featurec 结果?

为啥我的交叉验证错误分类错误率与测试数据集成功率相矛盾

为啥调用 python 列表的 [-1] 会给出这个输出? [复制]

python - 为啥在python中使用int()将二进制转换为整数会在将2作为基本参数时给出错误