2012-07-20 116 views
2

我写了一些非常简单的测试(我知道,它们不是'结论性',但它们让我好奇)。我跑了优化和所有的爵士乐。为什么Python的'all'函数太慢?

from time import time 

alist = [ 2, 4, 6, 8, 10, 12, 24, 48, 64, 128 ] 

def all_even(alist): 
    for val in alist: 
     if not (val & 1) == 0: 
      return False 
    return True 

def all_even_bad(alist): 
    result = False 
    for val in alist: 
     if not (val & 1) == 0: 
      result = False 
     else: 
      result = True 
    return result 

def main(): 
    start = time() 
    for i in range(1, 10000): 
     all_even(alist) 
    print('All even: {0}'.format(time() - start)) 

    start = time() 
    for i in range(1, 10000): 
     all_even_bad(alist) 
    print('All even bad: {0}'.format(time() - start)) 


    start = time() 
    for i in range(1, 10000): 
     all(val & 1 == 0 for val in alist) 
    print('All one: {0}'.format(time() - start)) 


if __name__ == '__main__': 
    main() 

我得到的结果周围:

> All even: 2.86299991608 
> All even bad: 3.71399998665 
> All one: 3.89900016785 

它出现在内置的功能不及早摆脱困境?

+2

这里肯定有什么可疑的。你只能循环10000次10000个列表。你的时间不应该在几秒钟的时间。还要注意,你的all_even_bad函数是完全错误的; ^)(它实际上只是检查最后一个元素)。 – mgilson 2012-07-20 17:21:00

+0

对不起 - 我有一堆测试,但没有想到发布所有的代码。我试图发布一个小但可运行的示例。 :) – 2012-07-20 17:22:59

回答

8

all()肯定会提前退出,我认为行为差异只是创建生成器所需开销的结果。

下面是一些证明all()不会退出早:

In [8]: alist = [3] + [0] * 2**20 # alist bigger, with an early odd 

In [10]: %timeit all_even(alist) 
1000000 loops, best of 3: 309 ns per loop 

In [11]: %timeit all_even_bad(alist) 
10 loops, best of 3: 133 ms per loop 

In [12]: %timeit all(val & 1 == 0 for val in alist) 
1000000 loops, best of 3: 891 ns per loop 

注意,即使all()慢于all_even()这里,它仍然是显著快于不提前退出函数的版本。

+0

发电机是每次迭代?为什么每个循环会比all_even高得多?如果仅仅是对象创造,那么我认为它应该只发生一次惩罚。 – 2012-07-20 17:17:25

+0

生成器在每次迭代时生成。与直接循环列表相比,这是一个小的但不变的开销,就像调用'all_even()'或'all_even_bad()'时那样。 – 2012-07-20 17:20:46

+0

啊,这很有道理。感谢:D – 2012-07-20 17:22:06

1

由于列表中的所有数字实际上都是偶数,所以它在逻辑上不能提早退出?您拨打all()的开销可能来自构建generator对象。

2

您没有测试失败的元件,因此无法短路。

+0

对不起,我写了几个测试(不少),但没有在这里包括所有的脚本。 – 2012-07-20 17:14:14