【问题标题】:Parallelize array creation并行化数组创建
【发布时间】:2012-11-21 02:12:19
【问题描述】:

F#

[|for index in 1 .. items.Count()-1 -> (* create object here - complex operations *)|]

C#

Object[] newItemArray= new Object[items.Count];

Parallel.For(0, items.Count, index=>
{
    /*complex stuff here*/
    newItemArray[index] = new Object();
});

我有上面的 C# 和 F# 做同样的事情。如果没有Parallel.For,F# 会稍微快一些。使用Parallel.For,C# 的执行时间减半。如何正确并行化 F# 以获得与 C# 相同的性能提升?

到目前为止,我尝试的方法是 Array.Parallel.Iteri,因此我可以在 C# 中使用的数组技巧中使用相同的索引,但它会减慢而不是加快速度。

编辑:

关于我在做什么的更多细节:

我有一个可枚举的byte array array array。我还有另一个byte array array array,我正在与其他人进行比较。我正在对可枚举的百分比相似度进行排序并返回前 500 个。

在 F# 和 C# 中,我都在做一个简单的嵌套 for 循环,它会增加一个计数器。当循环遍历我的可枚举中的特定项目时,我创建了一个 (item, counter) 的元组。完成创建新的 (item, counter) 可枚举项后,我对 counter 变量进行排序,获取前 500 个,然后转换回仅可枚举的项目。

我放入 Parallel.For 的部分是 IEnumerable<Tuple<item, int>> 的创建

【问题讨论】:

  • 我想是时候开始比较IL了...
  • 我知道这并不容易,但你能举一个可重现的例子吗?您编辑并没有多大帮助。

标签: f# array-initialization


【解决方案1】:
Array.Parallel.init items.Count (fun index ->
    (* create object here - complex operations *))

官方文档:Parallel.init<'T> Function (F#)

【讨论】:

  • @pad :不一定更快,只是缺少细节。 :-P
  • 由于某种原因,这需要我的顺序解决方案的 3 倍和我的并行 C# 解决方案的 7 倍。
  • @mydogisbox :您正在分析发布版本,而不是调试,对吧?
  • 它的发布和“启动而不调试”未定义“DEBUG”常量。
  • 明确地说,我使用Stopwatch 来计算运行时间,然后将经过的时间打印到控制台。
【解决方案2】:

在这种情况下,您不应该使用数组解析。它比高阶函数慢一点,不能并行化。

虽然我更喜欢 @ildjarn 的解决方案,但这里有一个与您的 C# 解决方案等效的解决方案:

// You need an uninitialized array to fill in later
let newItemArray = Array.zeroCreate items.Count

// Fill in the array in a parallel manner
Array.Parallel.iteri (fun i v ->
    (* create object here - complex operations *)) newItemArray

你也可以直接使用Parallel.For

let newItemArray = Array.zeroCreate items.Count 

Parallel.For(0, items.Count, 
             (fun index ->
                 (* complex stuff here *)
                 newItemArray.[index] <- Object())
) |> ignore

它更冗长,但让您可以更好地控制degree of parallelism

【讨论】:

  • iteri 是我尝试的第一种方法,只比我的顺序解决方案慢一点。 Parallel.For 解决方案比我的顺序解决方案耗时大约 3.5 倍。
  • 您能否在 F# Interactive 中与 #time "on";; 快速比较并行与顺序解决方案?没有更多细节很难猜测。
  • 我在他们周围有一个秒表。时间为:Parallel.For 解决方案为 1.025,iteri 解决方案为 0.436。我的顺序 F# 解决方案每次运行大约 0.360。
  • 我们需要有关 F# 和 C# 函数的更多详细信息。奇怪的是,当 C# 版本可以扩展时,F# 版本不能扩展。
  • 我想通了。我正在使用一些 ref 类型来解决一些并行性问题,结果证明这正在扼杀我的表现。删除其中的一些,然后使用 Array.Parallel.mapi,它就像一个魅力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-04
相关资源
最近更新 更多