2012-05-06 10 views
6

私は最近、予期せぬコードの最適化に直面し、私が観察していたことの解釈が正しいかどうかをチェックしたかったのです。以下の状況のはるかに簡単な例である:F#自動汎化とパフォーマンス

let demo = 
    let swap fst snd i = 
     if i = fst then snd else 
     if i = snd then fst else 
     i 
    [ for i in 1 .. 10000 -> swap 1 i i ] 

let demo2 = 
    let swap (fst: int) snd i = 
     if i = fst then snd else 
     if i = snd then fst else 
     i 
    [ for i in 1 .. 10000 -> swap 1 i i ] 

コードの2つのブロック間の唯一の違いは、第二のケースでは、私は明示的に整数としてスワップの引数を宣言することです。しかし、#時間でfsiで2つのスニペットを実行すると、

ケース1:00:00:00.011、CPU:00:00:00.000、GC gen0:0、gen1:0、gen2: 0
ケース2レアル:00:00:00.004、CPU:00:00:00.015は、GCのgen0:0は、GEN1:0は、GEN2:第二スニペットすなわち0

が3倍速く最初よりも実行されます。ここでの絶対的なパフォーマンスの違いは明らかに問題ではありませんが、私がスワップ機能をたくさん使用すると、それは積み重なります。

私は、最初のケースではスワップが一般的であり、 "等価性が必要"であると仮定し、intがそれをサポートしているかどうかをチェックするのに対し、後者の場合は何もチェックする必要はありません。これがこれが起こっている理由なのでしょうか、それとも私は他の何かを逃していますか?そしてもっと一般的には、私は自動化された一般化を両刃の剣、すなわち性能に予期しない影響を及ぼすかもしれないすばらしい特徴と考えるべきですか?

答えて

10

これは、質問Why is this F# code so slowとほぼ同じだと思います。その問題では、パフォーマンスの問題はcomparisonが必要な制約によって発生し、その場合はequalityという制約が原因です。

どちらの場合でも、コンパイルされたジェネリックコードはインターフェイス(およびボクシング)を使用する必要があります。特殊化されたコンパイル済みコードは、整数または浮動小数点数の比較または等価にIL命令を直接使用できます。

パフォーマンスの問題を回避するには、2つの方法があります。

  • あなたは
  • マークをしたとして、コンパイラが自動的に
それを専門とするよう inlineとしての機能を intfloatを使用するコードを特殊

小さな関数の場合は、コードがであまり生成されないため、2番目の方法が優れています。一般的な方法で機能します。単一の型だけの関数を(意図的に)使用する場合は、おそらく最初のアプローチを使用するのが適切です。

+0

おかげで、持っているとして、この問題は消えるだろうと思われます。したがって、私が正しく理解している場合、関数をインラインとしてマークすると、「この関数は汎用ですが、呼び出された場所で使用される型に基づいて特定のバージョンを作成しますか?数学スタイルのすべての関数をインラインとしてマークしない理由はありますか? – Mathias

+0

あるいは、別の言い方をすれば、「あまりコードを生成しない」ということを少し詳しく説明できますが、これはあまり理解できません。 – Mathias

+1

@Mathias 'inline'キーワードは、コンパイラが関数の呼び出しをその実装に置き換えることを意味します。これは、関数のコードがすべての呼び出しで1回繰り返されることを意味します。本当に長い関数の場合、アセンブリが大きくなります(またはJITに長時間かかる長いメソッドを生成する)。だからこそ私はこれを短い関数のためだけに使うことを勧めました。 –

3

違いの理由は、intバージョンはちょうど直接比較することができながら、コンパイラは、ジェネリック版で

IL_0002: call bool class [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericEqualityIntrinsic<!!0> (!!0, !!0) 

への呼び出しを生成していることです。

あなたがinlineを使用した場合、私は、コンパイラは今余分なタイプの情報に確かに非常に類似した他の質問へのポインタのための