我是否可以检查观察者是否有新物品到达观察者?

时间:2016-12-31 03:34:49

标签: c# .net system.reactive

我正在访问属于不同计算过程的内存区域。 该区域的变化相对较少,我需要在有变化时进行计算。我收到有关更改的通知,但我需要稍等一下,以确保不再进行任何更改。我这样建模:

var readyToBeProcessed = changed
    .Select(x => DateTime.Now)
    .Throttle(TimeSpan.FromSeconds(5));

然而,我的计算需要相当长的时间,并且在我执行这些操作时,内存可能会发生变化。在这种情况下,我需要将这一轮特定的计算标记为无效。

但是我在观察员中知道,当我完成计算时,是否有另一个事件到达,处理当前事件?如果自我开始计算后没有事件到达,那么它有效,我可以存储结果。

在实践中,很少发生事件到达模式(足够快),使计算无效,我仍然愿意照顾这种情况。

注意:我意识到我无法保证始终有效的计算。内存更改和接收事件的时间之间有一段时间。完全有可能,序列就像这样1)我正在进行计算2)记忆变化3)我完成计算并检查事件,并确定计算有效4)记忆变化事件到来。我现在很高兴与此同住

readyToBeProcessed.Subscribe(x =>
{
    Log.Info("Start work...");
    // Do calculation here
    ...
    // When finished
    if (Is there a new item)
    {
        Log.Info("There were changes while we worked... Invalidating");
        Invalidate();
    }
    else
    {
        Log.Info("Succeeded");
    }
}, cancellationToken);

Reactive不适合这项任务吗?

2 个答案:

答案 0 :(得分:1)

理想情况下,我建议您使用Task来跟踪您的工作,然后您可以使用:

readyToBeProcessed
.Select(evt => Observable.StartAsync<Unit>(async (cancellationToken) =>
{        
    //pass cancellationToken to work
    var result = await DoWork(cancellationToken);
    //test token if needed
    return result;
}))
.Switch()
.Subscribe();

当下一个项目到达时,当前令牌将被取消。

答案 1 :(得分:1)

我认为Rx实际上是一个很好的选择,尽管您可能需要更明确地对其进行建模。

想想真的有五种类型的事件:项目更改,工作开始,工作结束,无效和成功(我希望我可以使用更好的名字,但我正在处理你的事情写)。

这是一个关于它们如何工作的大理石图:

t(sec)        : 0--1--2--3--4--5--6--7--8--9--10-11-12-13-14-15-16...
item-change   : *-*--**-----------------*-------------------------...
do-Work-begins: ---------------------*-----------------*----------...
do-Work-ends  : -------------------------*------------------*-----...
invalidate    : -------------------------*------------------------...
succeeded     : --------------------------------------------*-----...

一旦项目更改暂停5秒,我们就开始工作。如果在工作时间内有任何变化,我们希望在工作完成时失效。如果没有,我们希望观察成功。

var doWorkBegins = changed
    .Select(x => DateTime.Now)
    .Throttle(TimeSpan.FromSeconds(5));

var doWorkEnds = doWorkBegins
    .SelectMany(x => 
    {
        Log.Info("Start work...");
        // DoWork();
        //
        // should return an observable that returns a single value when complete.
        // If DoWork is just a void, then can use 
        // return Observable.Return(Unit.Default);
    });

var lists = changed
    .Buffer(() => doWorkEnds)
    .Publish().RefCount();

var succeeded = lists
    .Where(l => l.Count == 0);

var invalidate = lists
    .Where(l => l.Count > 0);

invalidate.Subscribe(x =>
{
        Log.Info("There were changes while we worked... Invalidating");
        Invalidate();
}, cancellationToken);

succeeded.Subscribe(x => 
{
    Log.Info("Succeeded");
}, cancellationToken);