如何在复杂的分组设置中使用Rx Throttle throttleDurationSelector

时间:2013-10-28 17:20:40

标签: c# events system.reactive reactive-programming

所以,我问过如何在正在运行的查询[{3}}中间更改Throttle Timespan,here然后回复说有一个重载并且实际上也提供了一个示例(所有好的)好吧,我也从那里学到了一些技巧。)

在上周末,我制作了一段代码,其中Throttle间隔将由传入流本身定义。作为一个实际例子,流可以是一系列结构,定义如下

struct SomeEvent
{
    public int Id;
    public DateTimeOffset TimeStamp;
}

然后接受流将检查TimeStamp字段并根据它们计算缺勤间隔。改变詹姆斯的一些相关例子,可以像

那样产生流
Func<SomeEvent, IObservable<long>> throttleFactory = e => Observable.Timer(TimeSpan.FromTicks(throttleDuration.Ticks - (DateTimeOffset.Now.Ticks - e.TimeStamp.Ticks)));

var sequence = Observable.Interval(TimeSpan.FromSeconds(1)).Select(_ => new SomeEvent { Id = 0, TimeStamp = DateTimeOffset.Now.AddTicks(-1) }).Throttle(throttleFactory);
var subscription = sequence.Subscribe(e => Console.WriteLine(e.TimeStamp));

时间转移,几个滴答,仅用于说明目的

然后我有一个更详细的例子James,詹姆斯再次帮助了很多。简而言之,这里的想法是,每个ID(类似于交通信号灯)可能会有“警示灯塔”,颜色有黄色和红色,每个轮流都会根据缺少的时间点亮。事件。然后当事件到来时,所有灯都关闭,“缺席定时器”从零开始。

我遇到的障碍是我似乎无法改变这个特定的例子,因此它会使用这个想法来产生Throttle值。特别是我似乎无法在詹姆斯的代码here中在grp => grp.Throttle(thresholdSelector(grp.Key, level), scheduler))行上很好地进行分组。也许我在调试时太累了,但是如果有人可以提供正确的方向,我肯定会感激不尽!

有什么好主意?嗯,事件可能会在源头加上时间戳,但传输可能会增加需要考虑的延迟。从与分布式计算相关的F#用户组讨论(以及我自己对集成问题有点熟悉)来看,事件在某个地方加上时间戳然后通过不同的排队系统进行中继的场景会产生两种情况:

  1. 技术暂停:在某些情况下未发现任何事件 定义区间内的终点。
  2. 营业暂停:有可能 很多事件,例如暂时的,持续的事件爆发 从排队系统(甚至重复),但它们有时间戳 “很久以前”。
  3. &lt;编辑:对于我在 2。中给出的示例,Brandon提出了一个有效的观点。一个人应该如何解释缺少“业务超时”?如果事件尚未到达,则唯一有效的超时事件是 1中的“技术”事件。如果它们确实到达突发事件,接收器是否对事件之间的时差感兴趣并且想要相应地提高颜色事件?或者,应该根据业务事件中的时间戳重置计时器,然后在突发到达时,取最后一个的时间戳(再次,可能比允许的超时时间长)。它变得复杂和混乱,最好以此为例。

    在撰写本文时,我仍然有兴趣知道如何在grp => grp.Throttle(thresholdSelector(grp.Key, level), scheduler))中执行联接。如果情况变得复杂,我倾向于将Brandon的帖子标记为答案(因为我觉得它可能会得到,我觉得分组相当复杂)。

1 个答案:

答案 0 :(得分:1)

这听起来像节流不再是你想要的。这是你想要做的吗?

var alarms = events
    .GroupBy(e => e.Id)
    .SelectMany(grp =>
    {
        // Determine light color based on delay between events

        // go black if event arrives that is not stale
        var black = grp
            .Where(ev => (Date.Now - ev.TimeStamp) < TimeSpan.FromSeconds(2))
            .Select(ev => "black");

        // go yellow if no events after 1 second
        var yellow = black
            .Select(b => Observable.Timer(TimeSpan.FromSeconds(1)))
            .SwitchLatest()
            .Select(t => "yellow");

        // go red if no events after 2 seconds
        var red = black
            .Select(b => Observable.Timer(TimeSpan.FromSeconds(2)))
            .SwitchLatest()
            .Select(t => "red");

        return Observable
            .Merge(black, yellow, red)
            .Select(color => new { Id = grp.Key, Color = color });
    });