2012-02-28 13 views
1

私はC++のような言語で、クラス内で定義された仮想メソッドの呼び出しが非仮想メソッドを呼び出すよりも遅い理由を理解しています(呼び出すには正しい実装を参照するために動的ディスパッチテーブルを調べる必要があります)。なぜメソッドが遅いですか?

しかし、Pythonで、私が持っている場合:私は何を得ることはありませんが、なぜある

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

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

これは劇的に(40%についての私の実験で)より遅いですそれは非常に遅くする必要があります、メソッドのルックアップ(私は思います)は、呼び出しを減らすために発生するので、交差のメソッドが実際に呼び出される削減の内部は再び見上げる必要はありません(ちょうど再利用同じメソッド参照)。

私の理解に間違いがある場合、誰かを照らすことができますか?

+0

この差分が表示されますか多くの小さなセット、またはいくつかの大きなセットの場合は?私は最初のケースで問題にバインドする問題を期待しますが、実際の交差作業がオーバーヘッドを支配する後者では問題にはなりません。私は2つの矛盾する答え(そのうちの1つは2回)を見て、どちらが正しいのか分からない。 – ugoren

+0

小さい(約10セットのリスト)と中規模(ランダムに生成された約100セットのリスト)の両方のためのものでした。その理由は、以下の彼の答えでSvenによって説明された。 –

答えて

12

これは、メソッドバインディングなどとはまったく関係ありません。最初のバージョンは、各繰り返しで3つのセットの交差を計算し、2番目のバージョンは2つのセットと交差するだけです。明示的なループを代わりに使用すると、これは簡単にわかります。

バリアント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、そうだよ。ありがとう! –

+0

それでは、intersection_udpateを使ってループすると、set.intersectionを使ったreduceよりも速く(約3%)スムージングができました。 –

+0

@AdamParkin:非自明なケースではもっと大きな違いが予想されていたので、[私は自分でいくつかのタイミングを取った](https://gist.github.com/1934353)。実際、ループバージョンは 'reduce()'バージョンの2倍以上の速さであることがわかりました。すべての反復で新しいセットを作成する必要はありません*違いは違いますか? –

関連する問題