我有以下异步队列处理路由。
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是否有一种简单的方法。
感谢。
答案 0 :(得分:1)
这是一个比起初看起来更难的问题。您希望BlockingCollection
(以及基础ConcurrentQueue
)用于生产者 - 消费者作业语义。但是你也希望能够观察到这些集合发生了什么,包括等待“空”信号。
最好的办法是从这里查看JobQueue
和ParallelJobQueue
:
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)
在我看来,你的要求是
如果这些是您的要求,并且您没有被迫使用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个线程,而无需自定义调度程序。