[英]How to limit the number of threads created for an asynchronous Seq.map operation in F#?
当前的设置是这样的
array
|> Seq.map (fun item -> async { return f item})
|> Async.Parallel
|> Async.RunSynchronously
如果要并行化将数组(或任何序列)作为输入的CPU密集型计算,则最好使用F#PowerPack中的 PSeq
模块(尽管它仅在.NET 4.0中可用)。 它提供了许多标准Array.xyz
函数的并行版本。 有关更多信息,您还可以查看带有.NET示例的并行编程的 F#转换 。
解决您的问题的代码比使用工作流程要简单一些:
array |> PSeq.map f
|> PSeq.toArray
两种选择之间的一些区别是:
总之,如果您需要异步操作(例如I / O),那么Async
是最佳选择。 如果您有大量的CPU密集型任务,那么PSeq
可能是一个更好的选择(在.NET 4.0上)
这是一个根据Brian的建议,如何使用信号量来执行此操作的示例:
open System
let throttle n fs =
seq { let n = new Threading.Semaphore(n, n)
for f in fs ->
async { let! ok = Async.AwaitWaitHandle(n)
let! result = Async.Catch f
n.Release() |> ignore
return match result with
| Choice1Of2 rslt -> rslt
| Choice2Of2 exn -> raise exn
}
}
let f i = async { printfn "start %d" i
do! Async.Sleep(2000)
}
let fs = Seq.init 10 f
fs |> throttle 2 |> Async.Parallel |> Async.RunSynchronously |> ignore
您可能会做几件事。
首先,由于这使用了ThreadPool
,因此可以使用ThreadPool.SetMaxThreads
。
其次,您可以按照以下方式引入自己的节流阀:
let throttle = makeThrottle(8)
array
|> Seq.map (fun item -> async { do! throttle.Wait()
return f item})
|> Async.Parallel
|> Async.RunSynchronously
makeThrottle()
不会太难编写,但是会产生一些同步开销。 如果您试图并行化太多事情以致内存不足,那么节流开销很可能不是问题。 (如果您需要这种代码的样本,请告诉我。)
最后,如果这确实使事情崩溃了,它闻起来好像是您做错了什么。 ThreadPool
通常(但并非总是如此)在管理自身方面做得很好。 但是,在各种情况下,设计自己的节流阀对您的应用而言仍然很有价值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.