2012-02-28 175 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