11

Computer Language Benchmarks Game のThreadring の F# エントリには、一見役に立たない行が含まれています: if false then (). この行をコメントアウトすると、プログラムははるかに高速に実行され (50000000 の入力に対して ~2 秒と ~55 秒)、同じ結果が得られます。これはどのように作動しますか?なぜこの行があるのですか?ノーオペレーションのように見えるものに対して、コンパイラは正確に何をしているのでしょうか?

コード:

let ringLength = 503

let cells = Array.zeroCreate ringLength
let threads = Array.zeroCreate ringLength
let answer = ref -1

let createWorker i = 
    let next = (i+1)%ringLength
    async { let value = cells.[i]
            if false then () 
            match value with
            | 0 -> answer := i+1
            | _ -> 
                cells.[next] <- value - 1 
                return! threads.[next] }

[<EntryPoint>]
let main args = 
    cells.[0] <- if args.Length>0 then int args.[0] else 50000000
    for i in 0..ringLength-1 do 
        threads.[i]<-createWorker i

    let result = Async.StartImmediate(threads.[0])
    printfn "%d" !answer
    0
4

2 に答える 2

9

私はもともとこのコードを書きました。この行を追加した正確な理由は覚えていませんが、この行がないと、オプティマイザーがベンチマーク ゲームの精神に反することをしてしまうのではないかと推測しています。最初に非同期を使用する理由は、次の非同期への末尾呼び出しの継続を実現するためです (これにより、C# モノラルよりもはるかに優れたパフォーマンスが得られます)。- 上毛

于 2012-12-04T22:03:09.750 に答える
7

計算式にが含まれているif false then ()場合、非同期ワークフローは少し異なる方法で変換されます。行では、を使用しますasync.Combine。少し簡略化されたコードは次のようになります。

async.Delay(fun () ->
  value = cells.[i]
  async.Combine
    ( async.Return(if false then ())
      async.Delay(fun () ->
        match value with (...) ) ))

Combineループによって実行される(潜在的に)非同期計算ifを次のコードと組み合わせる必要があるため、変換が挿入されます。ここで、削除ifすると次のようになります。

async.Delay(fun () ->
  value = cells.[i]
  match value with (...) ) ))

違いは、に渡された関数ですぐに多くの作業が行われるようになったことDelayです。

編集:Async.StartImmediateコードがの代わりにを使用しているため、これが違いを引き起こしていると思いましたAsync.Startが、そうではないようです。実際、コードが非同期ワークフローを使用する理由がまったくわかりません...

編集II。:Monoについては完全にはわかりませんが、F#インタラクティブで確実に複製されます-そこでは、バージョンCombineが約4倍遅くなります(関数割り当てのオーバーヘッドのため、これは私が期待することです)。

于 2012-12-04T18:20:12.610 に答える