Каков эффект "if false then()" в записи игрового поля "Компьютерный язык" F # Threadring?

Компьютерные игры Benchmarks Game Запись F # для Threadring содержит, казалось бы, бесполезную строку: if false then (). Когда я прокомментирую эту строку, программа работает намного быстрее (~ 2s против 55 секунд для ввода 50000000) и дает тот же результат. Как это работает? Почему эта линия там? Что именно делает компилятор с тем, что кажется нерабочим?

Код:

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

Ответ 1

Если выражение вычисления содержит 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, выполняется намного больше работы.

EDIT: Я думал, что это вызвало разницу, потому что в коде вместо Async.Start используется Async.StartImmediate, но это, похоже, не так. На самом деле, я не понимаю, почему код использует асинхронные рабочие процессы вообще...

EDIT II.. Я не совсем уверен в Mono, но он определенно реплицируется в F # interactive - там версия с Combine примерно в 4 раза медленнее (что и есть Я ожидаю, из-за накладных расходов функции).

Ответ 2

Я написал этот код изначально. Я не помню точной причины, по которой я добавил линию, но я предполагаю, что без нее оптимизатор будет делать то, что, как я думал, было вне духа тестовой игры. Причиной использования асинхронов в первую очередь является достижение продолжения хвостового вызова до следующего async (что делает его намного лучше, чем С# mono). - Джомо