The Computer Language Benchmarks Game’s F# entry for Threadring contains a seemingly useless line: if false then (). When I comment out this line, the program runs much faster (~2s vs ~55s for an input of 50000000) and produces the same result. How does this work? Why is this line there? What exactly is the compiler doing with what appears to be a no-op?
The code:
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
If the computation expression contains
if false then ()then the asynchronous workflow gets translated a bit differently. With the line, it usesasync.Combine. Slightly simplified code looks like:The translation inserts
Combinebecause the (potentially) asynchronous computation done byifloop needs to be combined with the following code. Now, if you deleteifyou get something like:The difference is that now a lot more work is done immediately in the function passed to
Delay.EDIT: I thought this caused a difference because the code uses
Async.StartImmediateinstead ofAsync.Start, but that does not seem to be the case. In fact, I do not understand why the code uses asynchronous workflows at all…EDIT II.: I’m not entirely sure about Mono, but it definitely does replicate in the F# interactive – there, the version with
Combineis about 4 times slower (which is what I’d expect, because of the function allocation overhead).