如果我有一个异步值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绑定计算的正确方法?如果不是,什么是?
发布于 2015-03-27 18:20:30
确定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。
Update:由于并行不公开函数来“并行”调用操作,所以可能的解决方案如下所示:
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核上运行并将结果与“完整”核心解决方案进行比较可能是有用的。如果您有好的解决方案,那么在启用更多的核心时,您应该会看到一个线性的改进。仅在一个核心上运行的一种简单方法是设置ProcessorAffinity标志
let p = System.Diagnostics.Process.GetCurrentProcess ()
p.ProcessorAffinity <- 1n // Makes this process "single-core"(我正竭力抗拒回答你没有问过的问题,但我仍然因流感而虚弱)
PS。F# Async在许多方面都很棒,但它们主要是为了解决响应性问题,而不是可伸缩性问题。这意味着,如果您使用大量的Async工作流组合,您可能会丢失宝贵的时钟周期。不过,你发布的例子不会受到影响。对于与CPU绑定的问题,我倾向于使用Parallel,因为它使用自动缩放和工作窃取来利用所有的CPU资源,同时具有较低的开销。Task或hopac也是很好的替代品。
PS。如果你想自己管理缩放,我相信经验法则是核心数量的两倍。
PS。您说过忽略bound的同步问题,这是公平的,但我只想指出,如果一个共享资源经常被所有核心访问,那么性能可能不会有多大提高。
https://stackoverflow.com/questions/29303027
复制相似问题