有没有办法知道何时处理OnNext?

时间:2010-09-14 21:33:15

标签: system.reactive

我有一个管道设置都使用反应式扩展,从一个值流开始(可以随时到达)然后,订阅它有许多不同的“模块”输出计算值流,并且该流另一级别的模块也会订阅,这些模块也会计算其他值。

现在所有这一切的结尾都有一个类可以监听所有这些模块的值,并且会自己输出其他类型的值。

现在,在正常生活中,初始值流一直到达。

但我也希望能够“重播”这些值并获得所有输出,但这次“尽可能快”。

但我仍然需要这些值才有意义,即最终输出可以“回溯”到生成它的原始值。

不确定我是否有意义。

我正在考虑一些事情,但其中没有一件看起来真的很干净。

一个是“加速时间”。即,有一些时间扭曲和重放所有,比如说,以100倍速度或其他任何方式。这确实有一些显着的缺点,因为在100倍速度下,处理值的时间变得更加重要。

我想知道的另一个问题(并且导致我的问题)是能够“逐步”完成所有这一切,即有办法知道OnNext何时被其所有订户完全处理,所以我可以发送一个值,等待每个人处理它,获得相应的输出值,然后发送下一个。

它的优势在于它基本上可以“以我的电脑允许的速度”重播。

我想知道是否有某些东西我在某个地方遗失,或者某种方式来做我忽略的事情,这些事情可以很容易地做我想要的事情。

我没想到的唯一想法是为我的所有课程设置代理/外观,以拦截每个传入和传出的值并通知它,以便我的“重播者”能够跟踪所有。< / p>


我可能以糟糕的方式提出了我的问题。让我重新说一下。

我的问题不是“重播”这些值,我可以做得很好,即使只是从磁盘加载它们,并将它们放入IEnumerable,然后它们将尽快送入。

我的问题是,由于所有管道本质上都是多线程的,如果我这样发送它们,尽可能快,我将无法跟踪哪个输入值产生哪个输出值(与你的不同)例如,他们可能会彼此交织在一起)。

我想到了TimeStamped,但由于以下几个原因它对我没用:

  1. TimeStamped的分辨率几乎是DateTime.Now的分辨率,即10 ms不够精确且

  2. 再次,在基于时间的方法中,如果我的管道需要5毫秒来处理,那么突然这5毫秒需要太多意思(比如,在5毫秒内可能有很多输入值)本来就已经进来了,因此无法知道哪一个产生了哪个输出值。

  3. 我知道这听起来非常“模糊”,它肯定缺少一个小样本,但我不能把我的整个代码放在那里,因为它太长而复杂,我会尝试在某个方面得到一些小例子去。

    所有这些都是针对“模拟”环境,我可以重播昨天的值并回溯发生的事情和时间,但我可以更快地重播它们。

    非常感谢您的回复。

2 个答案:

答案 0 :(得分:1)

如果您希望通过重播完美复制多线程环境,那么它将变得简单或不可能。 (我知道愚蠢的陈述)。 1)如果你的worflow引入了并发性,即在产生值的源序列和值的最终消耗之​​间有多个调度程序或线程副作用(坏);那你就没有运气了。一旦你添加了scheduluing和线程,你将无法获得你正在寻找的准确性(5毫秒)。 2)但是,如果您只是由最终消费者应用调度(即在整个链中仅使用SubScribeOn&amp; ObserveOn一次),并且您还避免在管道中进行任何线程/调度或副作用构造;那么你有一些好消息。

遵循您只在最终订阅者中引入并发/调度的准则,您可以轻松地使用VirtualScheduler / TestScheduler来控制时间。它应该像梦一样工作,你可以加快时间,但仍然拥有Rx连续gaurantees的奢侈品。

这些指向我博客的链接也可能有所帮助:

http://leecampbell.blogspot.com/2010/06/rx-part-6-scheduling-and-threading.html

http://leecampbell.blogspot.com/2010/10/rx-part-8-testing-rx.html

答案 1 :(得分:0)

如果我在此理解您的要求,您希望能够重放您的可观察值流,而不会在每个推送值之间产生原始延迟。如果那是正确的,那么可以使用Replay扩展方法吗?

IConnectableObservable<TSource>
    Replay<TSource>(this IObservable<TSource> source);

这是我放在一起检查行为的测试代码:

var sw = new System.Diagnostics.Stopwatch();
sw.Start();

Action<string, int> writeLine = (t, n) =>
    Console.WriteLine("{0}: {1} @ {2} seconds",
        t, n,
        sw.Elapsed.TotalSeconds.ToString("0.000"));

var source = Observable
    .GenerateWithTime<int, int>
    (0, n => n < 5, n => n + 1, n => n,
    n => TimeSpan.FromSeconds(1.0));

var replay = source.Replay();

using (var replayConnect = replay.Connect())
{
    Action sourceFinally = () =>
    {
        replay.Run(n => writeLine("Replay", n));
    };
    source.Finally(sourceFinally).Run(n => writeLine("Source", n));
}

运行此代码的输出是:

Source: 0 @ 1.094 seconds
Source: 1 @ 2.115 seconds
Source: 2 @ 3.129 seconds
Source: 3 @ 4.143 seconds
Source: 4 @ 5.158 seconds
Replay: 0 @ 5.199 seconds
Replay: 1 @ 5.201 seconds
Replay: 2 @ 5.201 seconds
Replay: 3 @ 5.201 seconds
Replay: 4 @ 5.201 seconds

如果您需要知道推送原始值的时间,可以使用Timestamp扩展方法将可观察对象从IObservable<T>更改为IObservable<Timestamped<T>>

IObservable<Timestamped<TSource>>
    Timestamp<TSource>(this IObservable<TSource> source);

我不知道你是否抽了太多火锅,但这有助于你“排毒”吗? ; - )