2012-12-04 19 views
11

计算机语言基准游戏的F# entry for Threadring包含一个看似无用的行:if false then()。当我注释掉这一行时,程序运行速度要快得多(对于50000000的输入,大约2s vs 55s)并产生相同的结果。这个怎么用?这条线为什么在那里?编译器究竟在做什么看起来没有任何操作?在计算机语言基准游戏的F#线程环境条目中,“if then then()”的效果如何?

代码:

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 

回答

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倍(这是我期望的,因为函数分配开销)。

9

我原本写这段代码。我不记得我添加该行的确切原因,但我猜测,如果没有它,优化器会做我认为超出基准游戏精神的事情。首先使用异步的原因是为了实现下一个异步的尾部连续继续(这使得它的表现比C#单声道好得多)。 - 乔莫

+0

+1为一个权威的答案(如它是),但我很好奇你为什么要惩罚_a基准_的表现有意... – ildjarn

+2

回想起来,我相信我想要的展示不同的合法执行上下文的异步,同时仍然在同一个硬件线程上共享连续数据(对Go进行类似的使用模式)。如果没有这条线,F#会把整个事情放到一个有效的while循环中。对于基准测试来说,这样做会很花哨,但只要您尝试将代码用于某个真实的东西,性能就会下降20倍左右。 –