有没有办法通过引入调度程序来限制/限制Async.Parallel?我正在寻找执行Asq的Seq<' a>并行但不想超过某个小时限制。
我可以使用共享的可变变量,每个Async<' a>检查,但我想尽可能避免这种情况。
答案 0 :(得分:5)
在封面下,Async.Parallel
操作使用标准.NET线程池。所以,你可以配置线程池,但这可能不是一个好主意(你不应该阻塞线程池中的线程)。
如果我想实施一些限制,我可能会为此创建一个F#代理。代理为您提供了一种协调并发的非常简单的方法 - 它可能比使用可变变量(为此目的)更多的代码,但它为您提供了一个很好的抽象:
// We can ask the agent to enqueue a new work item;
// and the agent sends itself a completed notification
type ThrottlingMessage =
| Enqueue of Async<unit>
| Completed
let throttlingAgent limit = MailboxProcessor.Start(fun inbox -> async {
// The agent body is not executing in parallel,
// so we can safely use mutable queue & counter
let queue = System.Collections.Generic.Queue<_>()
let running = ref 0
while true do
// Enqueue new work items or decrement the counter
// of how many tasks are running in the background
let! msg = inbox.Receive()
match msg with
| Completed -> decr running
| Enqueue w -> queue.Enqueue(w)
// If we have less than limit & there is some work to
// do, then start the work in the background!
while running.Value < limit && queue.Count > 0 do
let work = queue.Dequeue()
incr running
do!
// When the work completes, send 'Completed'
// back to the agent to free a slot
async { do! work
inbox.Post(Completed) }
|> Async.StartChild
|> Async.Ignore })
要使用此功能,您可以创建具有指定限制的代理,然后调用Enqueue
添加您的工作项:
let w = throttlingAgent 5
for i in 0 .. 20 do
async { printfn "Starting %d" i
do! Async.Sleep(1000)
printfn "Done %d" i }
|> Enqueue
|> w.Post
这解决了与你的问题有点不同的问题 - 但它应该显示方向(而不是Completed
通知,你可能希望在后台发送一些async
每小时指定数量的“代币”。