我可以(安全地)在 Parallel.For 循环构造中写入数组吗?

Can I (safely) write to an Array in a Parallel.For loop construct?

下面的代码片段是否会为迭代范围内的所有索引正确写入 results

当有多个线程同时访问同一个对象时;由于索引,每个线程都写入内存中的唯一位置。

let results:NewType[] = Array.zeroCreate temp.Length
let mutable data = Unchecked.defaultof<OldType>

let loopResult = 
    System.Threading.Tasks.Parallel.For(
        0, 
        temp.Length, 
        (fun i -> 
            data <- temp.[i]
            results.[i] <- NewType(data.X, data.Y) 
        )
    )

由于 F# 数组的类型通常是 .NET System.Array 同时写入数组的不同部分将是线程安全的。已经讨论过了 HERE and HERE

按照您编写此代码的方式,它不会在并行迭代中正常运行。您添加了一个可变的临时对象,这将破坏您安全并行化此代码的能力。写入 results 是安全的,因为您知道每个线程将访问数组的不同元素,但是写入 data 是不安全的,因为许多线程可以同时分配给那个可变对象。

如果您这样重构代码:

let results:NewType[] = Array.zeroCreate temp.Length

let loopResult = 
    System.Threading.Tasks.Parallel.For(
        0, 
        temp.Length, 
        (fun i -> 
            let data = temp.[i]
            results.[i] <- NewType(data.X, data.Y) 
        )
    )

这样的行为就安全了。

然而,这段代码只是简单的并行映射,所以这样写会更惯用:

let loopResult = temp |> Array.Parallel.map (fun data -> NewType(data.X, data.Y))