我已经制作了一段大约运行的 java代码的“副本”. 400毫秒( https://gist.github.com/threecee/cb1c55ad1ce9ac4b1903).我在F#中使用Parallel.ForEach的版本,我也试过PSeq,但没有一个版本比7秒快. 并不是说我必
并不是说我必须让我的代码比我复制的代码更快,但我真的想知道在F#中如何在这样的示例计算中提高性能.
open System.Threading.Tasks #time let calculateProducts n = let bits = [| for i in 1 .. ((n+1)*(n+1)) -> 0 |] let inner i = [|i..n|] |> Array.map (fun j -> bits.[j*i] <- 1) |> ignore Parallel.ForEach([|1 .. n|], (fun i -> inner i)) |> ignore bits |> Array.sum printfn "%i" (calculateProducts 8000)
代码所做的是计算所有独特的产品x * y,其中x:1-> 8000和y:1-8000.
更新:
使用Array.init作为jpe在答案外观建议后更新的代码如下:
open System.Threading.Tasks #time let calculateProducts n = let bits = Array.init ((n+1)*(n+1)) (fun _ -> 0) let inner i = let arr = Array.init (n-i+1) (fun x -> x+i) Parallel.ForEach(arr, (fun j -> bits.[j*i] <- 1)) |> ignore let arr = Array.init n (fun x -> (x+1)) Parallel.ForEach(arr, (fun i -> inner i)) |> ignore bits |> Array.sum printfn "%i" (calculateProducts 8000)您需要使用内置数组初始化代码,因为您的当前数组初始化在示例中需要很长时间.从而更换线路
let bits = [| for i in 1 .. ((n+1)*(n+1)) -> 0 |]
用线
let bits = Array.init ((n+1)*(n+1)) (fun _ -> 0)
你应该获得与Java代码相当的性能.
更新:正如John Palmer建议的那样,Array.zeroCreate将使数组初始化为零更快.因此,如果您只需要将数组初始化为零而不计算任何初始值,那么请使用
let bits = Array.zeroCreate ((n+1)*(n+1))
更新:原因如此之快,之前已经解释过here.简短摘要:它使用适当的IL字节码命令newarr进行初始化,而后者又在.Net的运行时间内进行了优化,速度非常快. Array.init比直接“手动”初始化更快,因为它调用zeroCreateUnchecked来初始化数组,然后在已经初始化的数组上运行初始化函数.
如果你想知道代码在哪里,那么这里是链接:implementation of Microsoft.FSharp.Collections.Array反过来调用internal implementation in Microsoft.FSharp.Primitives.Basics.Array.