2017-04-20 67 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

如果沒有任何不便,請查看我的編輯 –