2012-01-12 7 views
2

プロジェクトで作業している間に、私は間違いなく1つの追加(未使用)引数を持つ同じメソッドが他のものよりも10倍も高速に実行できることに気付きました。 Stream.Formatよりもはるかに高速 ほぼ同等のメソッド間で素晴らしいパフォーマンスの差

type Stream() = 
    static member private write (x, o, a : byte[]) = (for i = 0 to 3 do a.[o + i] <- byte((x >>> 24 - i * 8) % 256)); 4 
    static member private format f x l = Array.zeroCreate l |> fun a -> (f(x, 0, a) |> ignore; a) 
    static member private format1 f x l o = Array.zeroCreate l |> fun a -> (f(x, 0, a) |> ignore; a) 
    static member Format (value : int) = Stream.format (fun (x: int, i, a) -> Stream.write(x, i, a)) value 4 
    static member Format1 (value : int) = Stream.format1 (fun (x: int, i, a) -> Stream.write(x, i, a)) value 4 

テスト

Stream.Format1実行、プライベートメンバー Stream.formatStream.format1の唯一の違いは、さらに法それ自体で使用されていないだけで o引数、ですが。

コンパイラはどのようにして異なる方法で2つのほぼ同じ方法を扱いますか?

編集:説明に感謝し、無知にごめんなさい。

+0

あなたがタイミングを取得するために実行しなかったどのように多くの反復? 1? 100万?キャッシュ効果、カーネルスケジューリングなどを円滑にするには、サンプルを十分に広げる必要があります。 – spraff

答えて

8

ただ1つの引数でFormat1を呼び出すと、関数が返されるという問題があります。実際の書式設定はまだ行われません。そして、あなたが実際に実際の最初のケースでは、フォーマット(つまり、配列を作成し、それに何かを書き込み)とのパフォーマンスのパフォーマンスを比較している...

Stream.Format 42 
Stream.Format1 42 

:これは、あなたがのパフォーマンスを比較する場合ことを意味し何もせずに関数の値を単に返すコード。

oのパラメータがformat1でない場合は、ダミー値を渡して実際に関数を評価して結果を得ることができます。その後、同様のパフォーマンスを取得する必要があります:

Stream.Format 42 
Stream.Format1 42() 
4

Formatは、実際にArray.zeroCreate l |> fun a -> (f(x, 0, a) |> ignore; a)を呼び出します。

Format1は、オブジェクトを渡したときにArray.zeroCreate l |> fun a -> (f(x, 0, a) |> ignore; a)を呼び出す関数を返します。

つまり、1つは実際の作業を行い、もう1つは部分的な関数アプリケーションです。後者は明らかに速いです。

あなたは部分関数のアプリケーションに慣れていない場合は、オーバー読む価値の「引数の部分適用」というタイトルのF#のドキュメント内のセクションがあります:Functions (F#)

関連する問題