使用Reactive Extensions(Rx)进行延迟和重复数据删除

时间:2011-01-19 16:52:44

标签: c# system.reactive reactive-programming

我想使用Reactive Extensions转换一些消息,并在一小段延迟后转发它们。

消息看起来像这样:

class InMsg
{
   int GroupId { get; set; }
   int Delay { get; set; }
   string Content { get; set; }
}

输出看起来像这样:

class OutMsg
{ 
   int GroupId { get; set; }
   string Content { get; set; }
   OutMsg(InMsg in)
   {
       GroupId = in.GroupId;
       Content = Transform(in.Content);  // function omitted
   }
}

有几个要求:

  • 延迟的长度取决于消息的内容。
  • 每条消息都有一个GroupId
  • 如果较新的消息带有与等待传输的延迟消息相同的GroupId,则应丢弃第一条消息,并在新的延迟期后仅传输第二条消息。

给出一个Observable< InMsg>和发送功能:

IObservable<InMsg> inMsgs = ...;

void Send(OutMsg o)
{
     ... // publishes transformed messages
}

据我所知,我可以使用Select执行转换。

void SetUp()
{
     inMsgs.Select(i => new OutMsg(i)).Subscribe(Send);
}
  • 如何应用指定延迟的消息? (注意这可能/应该导致消息的无序传递。)
  • 如何使用相同的GroupId对消息进行重复数据删除?
  • Rx能解决这个问题吗?
  • 还有另一种解决方法吗?

2 个答案:

答案 0 :(得分:9)

您可以使用GroupBy制作IGroupedObservableDelay来延迟输出,并使用Switch确保较新的值替换其组中的先前值:

IObservable<InMsg> inMessages;

inMessages
    .GroupBy(msg => msg.GroupId)
    .Select(group =>
        {
            return group.Select(groupMsg => 
                {
                    TimeSpan delay = TimeSpan.FromMilliseconds(groupMsg.Delay);
                    OutMsg outMsg = new OutMsg(); // map InMsg -> OutMsg here

                    return Observable.Return(outMsg).Delay(delay);
                })
                .Switch();
        })
        .Subscribe(outMsg => Console.Write("OutMsg received"));

关于实施的说明:如果在发送消息后(即延迟之后)到达,则会启动新的延迟

答案 1 :(得分:2)

@Richard Szalay回答几乎对我有用(在.NET Framework 4.6上使用.NET Rx 3.1.1),但我必须在最后添加.Merge()结合IObservable<IObservable<OutMsg>>结果的表达式,如下所示:

对我来说(在.NET Framework 4.6上使用.NET Rx 3.1.1),修复是将.Merge()添加到最后,如下所示:

var deduplicated = inputs
    .GroupBy(input => input)
    .Select(group =>
        group
        .Select(input => Observable.Return(input).Delay(TimeSpan.FromSeconds(5)))
        .Switch())
    .Merge(); // <-- This is added to combine the partitioned results