计算机语言基准测试游戏对于Threadring的F#条目包含一条看似无用的行:if false then ()
.当我注释掉这一行时,程序运行得更快(对于50000000的输入,~2s vs~55s)并产生相同的结果.这是如何运作的?为什么这条线路在那里?编译器到底做了什么似乎是无操作?
代码:
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
Run Code Online (Sandbox Code Playgroud)
我最初写了这段代码.我不记得我添加该行的确切原因,但我猜测,如果没有它,优化器会做一些我认为超出基准游戏精神的事情.首先使用asyncs的原因是为下一个异步实现尾部调用延续(这使得它的性能比C#mono好得多). - 乔莫
如果计算表达式包含,if false then ()
则异步工作流的转换有点不同.随着线,它使用async.Combine
.稍微简化的代码如下所示:
async.Delay(fun () ->
value = cells.[i]
async.Combine
( async.Return(if false then ())
async.Delay(fun () ->
match value with (...) ) ))
Run Code Online (Sandbox Code Playgroud)
转换插入Combine
是因为if
循环完成的(可能)异步计算需要与以下代码组合.现在,如果你删除if
你会得到类似的东西:
async.Delay(fun () ->
value = cells.[i]
match value with (...) ) ))
Run Code Online (Sandbox Code Playgroud)
不同之处在于,现在在传递给函数的过程中会立即完成更多工作Delay
.
编辑:我认为这导致了差异,因为代码使用Async.StartImmediate
而不是Async.Start
,但似乎并非如此.实际上,我不明白代码为什么会使用异步工作流......
编辑二.:我不完全确定Mono,但它肯定会在F#interactive中复制 - 在那里,版本的Combine
速度大约慢4倍(这是我所期望的,因为功能分配开销).
归档时间: |
|
查看次数: |
259 次 |
最近记录: |