与Async.Parallel调度 [英] Scheduling with Async.Parallel

查看:130
本文介绍了与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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆