如何并行对称工人?

时间:2015-03-27 14:25:21

标签: multithreading asynchronous parallel-processing f#

如果我有一个异步值work,我希望将其复制并并行执行,以便线程执行的硬件功能耗尽,我该怎么做?

例如,对于一个简短的具体示例,请考虑以下愚蠢的程序,该程序搜索小于1001的随机数:

let bound = ref System.Int32.MaxValue
let work = 
  async {
    let rand = new System.Random () 
    while !bound > 1000 do
      let x = rand.Next ()
      if x < !bound then
        bound := x
  }

[| work; work; work |] 
|> Async.Parallel
|> Async.RunSynchronously

(忽略bound的同步问题。)

在这里,我经营着三名工人;任何非零数字的程序都是正确的;当工人数量正好是可用核心数量时,可能效率更高。如何更改此程序,以便根据可用核心数自动选择工作人员数量?

更新即可。正在使用Async.Parallel并手动指示正确方式并行化CPU绑定计算的线程数,如上所述?如果没有,那是什么?

1 个答案:

答案 0 :(得分:3)

确定Process的可用内核数量的一种方法是这样的:

let numberOfAvailableCores () : int =
    let p = System.Diagnostics.Process.GetCurrentProcess().ProcessorAffinity

    let rec countOnes acc = function
        | 0un -> acc
        | n -> 
            let i = int (n &&& 1un)
            countOnes (acc + i) (n >>> 1)

    countOnes 0 (unativeint p)

我发现这比System.Environment.ProcessorCount更准确,因为AFAIK未能将ProcessorAffinity考虑进去。

更新:由于Parallel没有公开一个函数来调用一个动作&#34;并行&#34;一个可能的解决方案可能是这样的:

let numberOfAvailableCores () : int =
    let p = System.Diagnostics.Process.GetCurrentProcess().ProcessorAffinity

    let rec countOnes acc = function
        | 0un -> acc
        | n -> 
            let i = int (n &&& 1un)
            countOnes (acc + i) (n >>> 1)

    countOnes 0 (unativeint p)

let executeInParallel (a : unit->unit) : unit =
    let cores = numberOfAvailableCores ()

    let actions = 
        [|
            for x in 1..(cores * 2) -> Action a
        |]

    Parallel.Invoke actions

在尝试估算核心之间是否存在任何争用时的提示,只需在1核心上运行并将结果与​​&#34; full&#34;核心解决方案如果您有良好的解决方案,那么在启用更多内核时应该会看到线性改进。在1核上运行的一种简单方法是设置ProcessorAffinity标志

let p = System.Diagnostics.Process.GetCurrentProcess ()
p.ProcessorAffinity <- 1n // Makes this process "single-core"

(我正在尽最大努力拒绝回答你没有提出的问题,但我仍感染流感仍然很弱)

PS。 F#Async在许多方面都很棒,但它们主要用于解决响应性问题,而非 Scalability 问题。这意味着如果您使用大量Async工作流程,您可能会失去宝贵的时钟周期。你发布的例子不会受到影响。对于CPU绑定问题,我倾向于使用Parallel,因为它采用自动扩展和工作窃取来利用所有CPU资源,同时具有较低的开销。 Taskhopac也是不错的选择。

PS。如果你想自己管理扩展,我相信经验法则是核心数量的两倍。

PS。你说忽略了bound的同步问题,这是公平的,但我只想指出,如果一个人拥有经常被所有内核访问的共享资源,那么人们可能会看到很多性能提升。

相关问题