Reactive Extensions等待队列空

时间:2012-06-27 05:33:20

标签: .net asynchronous system.reactive

我有以下异步队列处理路由。

      var commandQueue = new BlockingCollection<MyCommand>();
      commandQueue
            .GetConsumingEnumerable()
            .ToObservable(new LimitedConcurrencyLevelTaskPoolScheduler(5))
            .Subscribe(c =>
                           {
                               try
                               {
                                   ProcessCommand(c);
                               }
                               catch (Exception ex)
                               {
                                   Trace.TraceError(ex.ToString());
                               }
                           }
            );

在一个特定场景中(当我即将获得一些数据时),我需要确保在出去获取数据之前我的commandQueue为空。预计此操作将同步进行。基本上,我想做像

这样的事情
  public void GetData()
  {
     commandQueue.WaitForEmpty(); 

     // could potentially be expressed: 
     // while (commandQueue.Count > 0) Thread.Sleep(10);

     return GoGetTheData()
  }

我意识到在一个理想的情况下,所有调用者都会“GetData”异步......但有时它必须以同步的方式发生......所以我需要等待命令队列为空以确保我的数据的一致性和最新性。

我知道如何使用ManualResetEvent轻松完成这项工作......但我想知道System.Reactive / TPL是否有一种简单的方法。

感谢。

3 个答案:

答案 0 :(得分:1)

这是一个比起初看起来更难的问题。您希望BlockingCollection(以及基础ConcurrentQueue)用于生产者 - 消费者作业语义。但是你也希望能够观察到这些集合发生了什么,包括等待“空”信号。

最好的办法是从这里查看JobQueueParallelJobQueue

http://social.msdn.microsoft.com/Forums/en-US/rx/thread/2817c6e5-e5a4-4aac-91c1-97ba7de88ff7

其中包括WhenQueueEmpty的observable,可以控制同时运行的作业和排队作业的数量(在这种情况下,作业与您的命令概念同义)。

答案 1 :(得分:0)

你能用吗?

    var dataObservable = Observable.Start(() =>
    {
        commandQueue.WaitForEmpty(); 
        return GoGetTheData();
    });

答案 2 :(得分:0)

在我看来,你的要求是

  • 异步获取数据
  • 并行处理此数据(最多5个并行度)
  • 重复此过程

如果这些是您的要求,并且您没有被迫使用BlockingCollection,即它不是现有的API,那么我认为您可以使用Rx轻松解决这个问题。

var dataRequestScheduler = new EventLoopScheduler();
var subscription = GetTheData()
    .Repeat()
    .SubscribeOn(dataRequestScheduler)
    .ObserveOn(Scheduler.TaskPool)//new LimitedConcurrencyLevelTaskPoolScheduler(5)
    .Subscribe(c =>
           {
               try
               {
                   ProcessCommand(c);
               }
               catch (Exception ex)
               {
                   Trace.TraceError(ex.ToString());
               }
           }
        );

GetTheData方法返回IObservable的位置

您可以利用Observable.Start和Merge(5)来获取最多5个线程,而无需自定义调度程序。