9

これらは2つの関数であり、fun11つのパラメーターをfun2取り、4つの余分な役に立たないパラメーターを取ります。x64をターゲットにした場合、fun14秒fun2かかりますが、1秒未満かかります。anycpuをターゲットにした場合、どちらも1秒未満で完了します。

ターゲットがx64の場合、 Seq.iter がforループより2倍速いのはなぜですか?

.Net 4.5 Visual Studio 2012、F#3.0でコンパイルされ、Windows7x64で実行されます

open System
open System.Diagnostics

type Position =
    {
        a: int
        b: int
    }

[<EntryPoint>]
let main argv = 

    let fun1 (pos: Position[]) =  //<<<<<<<< here
        let functionB x y z = 4

        Array.fold2 (fun acc x y -> acc + int64 (functionB x x y)) 0L pos pos

    let fun2 (pos: Position[]) u v w x =  //<<<<<<<< here
        let functionB x y z = 4

        Array.fold2 (fun acc x y -> acc + int64 (functionB x x y)) 0L pos pos



    let s = {a=2;b=3}
    let pool = [|s;s;s|]

    let test1 n =
        let mutable x = 0L
        for i in 1 .. n do
            x <- fun1 pool

    let test2 n =
        let mutable x = 0L
        for i in 1 .. n do
            x <- fun2 pool 1 2 3 4

    let sw = new Stopwatch()
    sw.Start()
    test2 10000000
    sw.Stop()
    Console.WriteLine(sw.Elapsed)

    sw.Restart()
    test1 10000000
    sw.Stop()
    Console.WriteLine(sw.Elapsed)


    0 // return an integer exit code
4

2 に答える 2

2

これは完全な答えではなく、問題の最初の診断です。

同じ構成で動作を再現できます。で F# Interactive 64 ビットをオンにTools -> Options -> F# Tools -> F# Interactiveすると、同じ動作が見られます。

他の質問とは異なり、x64 ジッターは問題ではありません。Project プロパティの「Generate tail calls」test1オプションは、 に比べてかなりの速度低下を引き起こすことがわかりましたtest2。このオプションをオフにすると、2 つのケースが同様の速度になります。

一方、テール コールが不要になるように、inlineキーワード onを使用できます。fun12 つの例は、fun2インライン化されているかどうかに関係なく、実行時間で比較できます。

そうは言っても、tail.オペコードを追加fun1すると (と同じことを行う) よりもはるかに遅くなるのは奇妙ですfun2。詳細な調査については、F# チームにお問い合わせください。

于 2012-11-08T14:01:57.513 に答える
0

この違いは、ほぼ間違いなく JITer の癖です。また、一貫性のない結果についても説明します。これは、このようなマイクロ ベンチマーク テストでよくある問題です。舞台裏で全体をコンパイルし、最後のものを計るために、メソッドの 1 つ以上の冗長な実行を実行します。それらは同一になります。

この癖により、これよりも奇妙な結果が得られる可能性があります。

于 2012-10-07T08:27:37.010 に答える