2012-02-28 171 views
1

好吧,我理解像C++這樣的語言,爲什麼在類中定義的調用虛擬方法比調用非虛擬方法要慢(您必須通過動態調度表來查找調用的正確實現)。爲什麼方法很慢?

但是在Python,如果我有:

list_of_sets = generate_a_list_containg_a_bunch_of_sets() 
intersection_of_all = reduce(list_of_sets[0].intersection, list_of_sets) 

這是大幅(在我的實驗中約40%)慢於:

list_of_sets = generate_a_list_containg_a_bunch_of_sets() 
intersection_of_all = reduce(set.intersection, list_of_sets) 

我不明白的是爲什麼這應該是慢得多,方法查找(我認爲)會發生在減少的調用,所以減少內部的交集方法實際調用時不應該再次查找(它只是重用相同的方法參考)。

有人能照亮這裏我的理解是有缺陷?

+0

你看見這個differenc e對於很多小套,還是對於一些大套?我希望綁定問題在第一種情況下很重要,但不在後者中(當實際的交叉工作主宰開銷時)。我看到兩個相互矛盾的答案(其中一個是兩次),並且無法確定哪個答案是正確的。 – ugoren 2012-02-28 17:38:28

+0

這是一個小的(約10套的清單)和中等(約100套隨機產生的清單)。 Sven在他的回答中解釋了這個原因。 – 2012-02-28 18:25:15

回答

12

這是完全無關的方法的結合等。第一版本計算的三組在每次迭代中的交叉點,而第二版本只相交兩個集合。如果我們使用顯式循環,這很容易看出來。

變體1:

intersection = list_of_sets[0] 
for s in list_of_sets[1:]: 
    intersection = list_of_sets[0].intersection(intersection, s) 

變2:

intersection = list_of_sets[0] 
for s in list_of_sets[1:]: 
    intersection = set.intersection(intersection, s) 

(請問你同意現在圭多有一個點?)

注意,這可能會是更快:

intersection = list_of_sets[0] 
for s in list_of_sets[1:]: 
    intersection.intersection_update(s) 
+0

AHHHHHHH,好的,我明白了。謝謝! – 2012-02-28 18:24:12

+0

yup,與intersection_udpate循環比使用set.intersection的reduce更快(約3%)。 – 2012-02-28 18:42:15

+0

@AdamParkin:因爲我預計非平凡的情況會有更大的差異,所以[我自己做了一些時間點](https://gist.github.com/1934353)。事實上,我發現循環版本比'reduce()'版本快兩倍以上。不必在每次迭代中創建一個新的集合*都應該有所作爲! – 2012-02-28 18:53:41