[英]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.