与Async.Parallel调度 [英] Scheduling with Async.Parallel
问题描述
有没有什么办法,Async.Parallel可以限制/通过引入调度节流?我期待执行异步℃的序列;一>平行,但不希望超过一定的小时限制
Is there any way that Async.Parallel can be limited/ throttled by introducing a scheduler? I'm looking to execute a Seq of Async<'a> in parallel but don't want to exceed a certain hourly-limit.
我可以使用一个共享的可变变量,每个异步&LT;'一>检查,但我想如果可能避免这种
I could use a shared mutable variable that each Async<'a> examines but I'd like to avoid this if possible.
推荐答案
在封面上,在 Async.Parallel
操作使用标准的.NET线程池。所以,你可以配置线程池,但是这可能不是一个好主意(你不应该在一个线程池阻塞线程)。
Under the cover, the Async.Parallel
operation uses the standard .NET thread pool. So, you could configure the thread pool, but that's probably not a good idea (you should not be blocking threads in a thread pool).
如果我想实现一些限制,我可能会创建一个这样的F#代理。代理商给你一个pretty简单的方式来协调并发性 - 它可能是更code比使用可变变量(为此),但它给你一个很好的抽象:
If I wanted to implement some throttling, I would probably create an F# agent for this. Agents give you a pretty simple way to coordinate the concurrency - it is probably more code than using mutable variable (for this purpose), but it gives you a nice abstraction:
// 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 })
要使用此功能,您可以创建一个与代理指定的限制,然后调用排队
添加您的工作项目:
To use this, you can create an agent with a specified limit and then call Enqueue
to add your work items:
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
这是解决比你有一个有点不同的问题 - 但它应该显示的方向(而不是让已完成
的通知,你可能希望有一些异步
在发送令牌每隔一小时)。
This is solving a bit different problem than the one you have - but it should show the direction (rather than having the Completed
notification, you probably want to have some async
in the background that sends a specified number of "tokens" every hour).
这篇关于与Async.Parallel调度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!