2014-08-31 69 views
7

我前些日子做了一個有趣的觀察。我正在嘗試各種方式來獲得對象的「真實性」和每個對象的速度,並且我注意到not很多快於bool爲什麼「不」比Python中的「bool()」更快(或者,Python函數的速度與語句的速度)?

>>> bool([5, 6, 7]) 
True 
>>> bool([]) 
False 
>>> not not [5, 6, 7] 
True 
>>> not not [] 
False 
>>> import timeit 
>>> from numpy import mean 
>>> mean(timeit.repeat('bool(a)', 'a = [5, 6, 7]', repeat=10)) 
0.19072036743164061 
>>> mean(timeit.repeat('bool(a)', 'a = []', repeat=10)) 
0.18562331199645996 
>>> mean(timeit.repeat('not not a', 'a = [5, 6, 7]', repeat=10)) 
0.072056698799133304 
>>> mean(timeit.repeat('not not a', 'a = []', repeat=10)) 
0.073475956916809082 
>>> mean(timeit.repeat('not a', 'a = [5, 6, 7]', repeat=10)) 
0.043941426277160647 
>>> mean(timeit.repeat('not a', 'a = []', repeat=10)) 
0.044287109375000001 

我們可以看到,使用bool功能比使用not聲明顯著慢,即使最終他們做同樣的事情(返回對象的布爾狀態)。現在,我們都被告知,在Python函數的開銷很大,但我沒想到在這種情況下,這種類型的差異,原因如下:

  • bool()是一個內置的功能,這意味着它是寫在C語言中,我預計這會有一個相當低的開銷
  • 在這兩種情況下,Python都必須在內部評估對象的「真實性」(我想他們會使用相同的C例程在內部執行此操作)
    • 實際上,not必須返回邏輯相對的對象的「感實性」,所以理論上它做一點更多的工作(但也許有一個實現細節,圍繞這得到)

在我的腦海裏,因爲這兩個功能基本上做同樣的事情全部額外的時間必須來自函數開銷。如果是這樣的話,爲什麼一個聲明能夠避免比一個函數有太多的開銷?如果不是開銷,爲什麼bool()not慢得多?


更新:這裏也是最小時間除了平均值。

>>> min(timeit.repeat('bool(a)', 'a = [5, 6, 7]', repeat=10)) 
0.18180489540100098 
>>> min(timeit.repeat('bool(a)', 'a = []', repeat=10)) 
0.1821761131286621 
>>> min(timeit.repeat('not not a', 'a = [5, 6, 7]', repeat=10)) 
0.0707249641418457 
>>> min(timeit.repeat('not not a', 'a = []', repeat=10)) 
0.07100605964660645 
>>> min(timeit.repeat('not a', 'a = [5, 6, 7]', repeat=10)) 
0.04264092445373535 
>>> min(timeit.repeat('not a', 'a = []', repeat=10)) 
0.04357004165649414 
+1

顛倒一個人比較的方式不會比其他方向花費更多的時間 - 如果你知道程序集,請考慮一下'je'和'jne';他們都只是一個指令。 – 2014-08-31 17:00:29

+1

......除此之外,請考慮一下函數調用_does_ - 這裏涉及到大量的堆棧調整。 – 2014-08-31 17:01:36

+0

我不知道大會,但這是有道理的。它仍然沒有解釋速度差異,但:) :) – SethMMorton 2014-08-31 17:01:42

回答

0

所有的函數調用都有相當大的開銷 - 畢竟,您正在創建一個新的堆棧框架來容納新的當地人。

如果這是一個更昂貴的操作,那麼開銷會在噪音中丟失。既然你正在尋找這樣一個小小的操作,它就很突出。

+0

爲什麼'not'語句會繞過那個開銷? – SethMMorton 2014-08-31 17:05:58

+0

@SethMMorton,...因爲它在現有的堆棧幀內運行。 – 2014-08-31 17:06:26

+0

因爲它是一個特殊的字節碼操作('UNARY_NOT')。 – filmor 2014-08-31 17:06:34

3

(這是不應該是一個答案,只是文檔):這些是給定表達式的字節碼序列:

bool(a)

1   0 LOAD_NAME    0 (bool) 
      3 LOAD_NAME    1 (a) 
      6 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
      9 RETURN_VALUE 

not a

1   0 LOAD_NAME    0 (a) 
      3 UNARY_NOT 
      4 RETURN_VALUE 

not not a

1   0 LOAD_NAME    0 (a) 
      3 UNARY_NOT 
      4 UNARY_NOT 
      5 RETURN_VALUE 
+0

很明顯'UNARY_NOT'比'CALL_FUNCTION'更有效率。但是,正如@delnan所指出的,兩者都必須調用對象的__bool__方法來確定布爾值。那麼,'bool'調用這個'UNARY_NOT'不是什麼額外的東西呢? – SethMMorton 2014-08-31 17:19:15

+0

好吧,'bool'被稱爲Python函數,並在'globals'中引入了額外的查找。請注意,這裏的每個操作都是非常便宜的,所以這可能是顯着的差異。 – filmor 2014-08-31 17:21:21

+0

嗯,在我的機器上,表達式'bool(True)'與bool(a)'完全一樣快地估計,'bool'的計算速度只比'not a'慢得多,所以'CALL_FUNCTION'實際上是這裏的「問題」 。 – filmor 2014-08-31 17:26:44

相關問題