2017-04-20 89 views
1
l = [1,0,0,1,1] 

count = 0 
start = time() 
for _ in range(100000): 
    for x in range(len(l)-1): 
     for y in range(x+1, len(l)): 
      if l[x] + l[y] == 1: 
       count += 1 
end = time() 
count2 = 0 
start2 = time() 
for _ in range(100000): 
    for x in range(len(l)-1): 
     for y in range(x+1, len(l)): 
      if l[x]^l[y]: 
       count2 += 1 
end2 = time() 

print str(count) + ' : Add and compare took: ' + str((end - start)/100000) 
print str(count2) + ' : Bitwise took: ' + str((end2 - start2)/100000) 

从我对位操作的理解中,他们应该比简单的比较更快。然而,这两个循环的速度完全相同(不会过分挑剔)。为什么这两个循环的速度完全相同?

当整数比较看起来一样快时,使用可以说比较复杂的按位运算而不是整数比较有什么好处?

编辑:

看来操作码并不都是相同的。

奥斯汀的答复中提到,这两个操作之间的差异有3个操作码VS 1,但是,下面的例子中具有相同数量的操作码,但显著不同的表现:

i = j = 10 

def test1(): 
    if i == j: 
     print True 

def test2(): 
    if not i-j: 
     print True 

print 'test 1' 
start1 = time() 
test1() 
end1 = time() 
dis(test1) 
print 'test 2' 
start2 = time() 
test2() 
end2 = time() 
dis(test2) 
print 'Test 1 took: ' + str(end1 - start1) 
print 'Test 2 took: ' + str(end2 - start2) 

这将输出:

test 1 
True 
25   0 LOAD_GLOBAL    0 (i) 
       3 LOAD_GLOBAL    1 (j) 
       6 COMPARE_OP    2 (==) 
       9 POP_JUMP_IF_FALSE  20 

26   12 LOAD_GLOBAL    2 (True) 
      15 PRINT_ITEM   
      16 PRINT_NEWLINE  
      17 JUMP_FORWARD    0 (to 20) 
     >> 20 LOAD_CONST    0 (None) 
      23 RETURN_VALUE   
test 2 
True 
29   0 LOAD_GLOBAL    0 (i) 
       3 LOAD_GLOBAL    1 (j) 
       6 BINARY_SUBTRACT  
       7 POP_JUMP_IF_TRUE  18 

30   10 LOAD_GLOBAL    2 (True) 
      13 PRINT_ITEM   
      14 PRINT_NEWLINE  
      15 JUMP_FORWARD    0 (to 18) 
     >> 18 LOAD_CONST    0 (None) 
      21 RETURN_VALUE   
Test 1 took: 7.86781311035e-06 
Test 2 took: 5.00679016113e-06 

有没有更准确的测量效率的方法?

编辑:

操作码创建几乎相等。

修改代码以排除讨厌的I/O显示了为什么I/O有问题。

i = j = 10 
bool1 = False 
bool2 = False 

def test1(): 
    if i == j: 
     bool1 = True 

def test2(): 
    if not i-j: 
     bool2 = True 

print 'test 1' 
start1 = time() 
for _ in range(1000000): 
    test1() 
end1 = time() 
dis(test1) 
print 'test 2' 
start2 = time() 
for _ in range(1000000): 
    test2() 
end2 = time() 
dis(test2) 
print str(bool1) + ' : Test 1 took: ' + str(end1 - start1) 
print str(bool2) + ' : Test 2 took: ' + str(end2 - start2) 

会打印:

test 1 
27   0 LOAD_GLOBAL    0 (i) 
       3 LOAD_GLOBAL    1 (j) 
       6 COMPARE_OP    2 (==) 
       9 POP_JUMP_IF_FALSE  21 

28   12 LOAD_GLOBAL    2 (True) 
      15 STORE_FAST    0 (bool1) 
      18 JUMP_FORWARD    0 (to 21) 
     >> 21 LOAD_CONST    0 (None) 
      24 RETURN_VALUE   
test 2 
31   0 LOAD_GLOBAL    0 (i) 
       3 LOAD_GLOBAL    1 (j) 
       6 BINARY_SUBTRACT  
       7 POP_JUMP_IF_TRUE  19 

32   10 LOAD_GLOBAL    2 (True) 
      13 STORE_FAST    0 (bool2) 
      16 JUMP_FORWARD    0 (to 19) 
     >> 19 LOAD_CONST    0 (None) 
      22 RETURN_VALUE   
False : Test 1 took: 0.156816959381 
False : Test 2 took: 0.16281914711 

所以还不如破釜沉舟,但还是很略有不同。这与测试1一起运行〜12次,只需要更长一次。

所以还是有一些谜!只有不那么激烈。

+0

'如果l [x] + l [y] == 1'不等于'if l [x]^l [y]' –

+0

功能上它在这个例子中。这个问题最初是为什么它们速度相同,而不是相同。 –

回答

3

你的循环中的所有代码基本上都是一样的,所以我将它们清除了。相反,我是你的代码减少到两个功能,并问我的好朋友dis.dis给我看他们在做什么:

l = [1,0,0,1,1] 

def f1(): 
    x = y = 0 
    if l[x] + l[y] == 1: 
     count += 1 

def f2(): 
    x = y = 0 
    if l[x]^l[y]: 
     count2 += 1 


import dis 
print "F1" 
dis.dis(f1) 
print "F2" 
dis.dis(f2) 

下面是输出:

$ python2.7 test.py 
F1 
    4   0 LOAD_CONST    1 (0) 
       3 DUP_TOP 
       4 STORE_FAST    0 (x) 
       7 STORE_FAST    1 (y) 

    5   10 LOAD_GLOBAL    0 (l) 
      13 LOAD_FAST    0 (x) 
      16 BINARY_SUBSCR 
      17 LOAD_GLOBAL    0 (l) 
      20 LOAD_FAST    1 (y) 
      23 BINARY_SUBSCR 
      24 BINARY_ADD       ## Here. 
      25 LOAD_CONST    2 (1)  ## Here. 
      28 COMPARE_OP    2 (==)  ## Here. 
      31 POP_JUMP_IF_FALSE  47 

    6   34 LOAD_FAST    2 (count) 
      37 LOAD_CONST    2 (1) 
      40 INPLACE_ADD 
      41 STORE_FAST    2 (count) 
      44 JUMP_FORWARD    0 (to 47) 
     >> 47 LOAD_CONST    0 (None) 
      50 RETURN_VALUE 
F2 
    9   0 LOAD_CONST    1 (0) 
       3 DUP_TOP 
       4 STORE_FAST    0 (x) 
       7 STORE_FAST    1 (y) 

10   10 LOAD_GLOBAL    0 (l) 
      13 LOAD_FAST    0 (x) 
      16 BINARY_SUBSCR 
      17 LOAD_GLOBAL    0 (l) 
      20 LOAD_FAST    1 (y) 
      23 BINARY_SUBSCR 
      24 BINARY_XOR       ## Here. 
      25 POP_JUMP_IF_FALSE  41 

11   28 LOAD_FAST    2 (count2) 
      31 LOAD_CONST    2 (1) 
      34 INPLACE_ADD 
      35 STORE_FAST    2 (count2) 
      38 JUMP_FORWARD    0 (to 41) 
     >> 41 LOAD_CONST    0 (None) 
      44 RETURN_VALUE 

不同的是3个操作码与1。这些操作的设置是6个操作码。噪音中的差异就会消失。

+0

令人惊叹!这正是我所期待的,再加上我从来没有听说过'dis'。很酷! –

+1

@NickA老实说,我怀疑它。解释器在这些循环中不必做很多工作,所以一切都可能被缓存。 –

+0

如果没有任何不便,请查看我的编辑 –