Rx.Net GroupBy实现缺少元素序列很少

时间:2016-10-27 06:07:31

标签: c# .net system.reactive reactive-programming rx.net

我正在使用RX 2.2.5。我有2个视图,用

加载子订单
           _transportService
            .ObserveSubOrder(parentOrder.OrderId)
            .SubscribeOn(_backgroundScheduler)
            .ObserveOn(_uiScheduler)
            .Where(subOs => subOs != null)                
            .Snoop("BeforeGrpBy")
            .GroupBy(subOs => subOs.OrderId)
            .Subscribe(subOrdUpdates =>
            {
                AddIfNew(subOrdUpdates.Key, subOrdUpdates.Snoop("AfterGrpBy" + "--" + subOrdUpdates.Key));                        
            })

在groupBy之前它获得所有元素序列,在groupby之后出现问题,它很少错过元素序列。我不会想到它的并发问题,因为它从日志中可以看出。自定义Snoop扩展方法用于生成这些日志。

16:15:44.8169968 : (1) : BeforeGrpBy: OnNext({ OrderId = 9Zsj8Z4sTRb, OrderType = WNX6, Quantity = 10, Price = 178.78125})
16:15:44.8169968 : (1) : AfterGrpBy--9Zsj8Z4sTRb: Observable obtained
16:15:44.8369988 : (9) : AfterGrpBy--9Zsj8Z4sTRb: Subscribed to on.
16:15:44.8379989 : (1) : BeforeGrpBy: OnNext({ OrderId = 9Zsj8Z4sTRb, OrderType = WNX6, Quantity = 10, Price = 178.78125})
16:15:44.8379989 : (9) : AfterGrpBy--9Zsj8Z4sTRb: Subscription completed.
16:15:44.8590010 : (1) : AfterGrpBy--9Zsj8Z4sTRb: Observable obtained
16:15:44.8600011 : (9) : AfterGrpBy--9Zsj8Z4sTRb: Subscribed to on.
16:15:44.8610012 : (9) : AfterGrpBy--9Zsj8Z4sTRb: Subscription completed.
16:15:44.8620013 : (1) : AfterGrpBy--9Zsj8Z4sTRb: OnNext({ OrderId = 9Zsj8Z4sTRb, OrderType = WNX6, Quantity = 10, Price = 178.78125})
  

格式化时间:(线程):消息

正如你在groupby onNext之前看到的那样被调用两次,但在它错过之后。 这里的Rx语法有问题还是已知的问题?任何见解都有帮助吗?如果需要进一步澄清,请发表评论。

更新 添加工作/期望日志:

16:15:45.1070258 : (1) : BeforeGrpBy: OnNext({ OrderId = 44Fqp3ubNmL, OrderType = TTT6, Quantity = 39, Price = 130.21875})
16:15:45.1280279 : (1) : AfterGrpBy--44Fqp3ubNmL: Observable obtained
16:15:45.1310282 : (10) : AfterGrpBy--44Fqp3ubNmL: Subscribed to on.
16:15:45.1320283 : (10) : AfterGrpBy--44Fqp3ubNmL: Subscription completed.
16:15:45.1320283 : (1) : AfterGrpBy--44Fqp3ubNmL: OnNext({ OrderId = 44Fqp3ubNmL, OrderType = TTT6, Quantity = 39, Price = 130.21875})
16:15:45.1330284 : (1) : BeforeGrpBy: OnNext({ OrderId = 44Fqp3ubNmL, OrderType = TTT6, Quantity = 39, Price = 130.21875})
16:15:45.1330284 : (1) : AfterGrpBy--44Fqp3ubNmL: Observable obtained
16:15:45.1340285 : (10) : AfterGrpBy--44Fqp3ubNmL: Subscribed to on.
16:15:45.1340285 : (10) : AfterGrpBy--44Fqp3ubNmL: Subscription completed.
16:15:45.1350286 : (1) : AfterGrpBy--44Fqp3ubNmL: OnNext({ OrderId = 44Fqp3ubNmL, OrderType = TTT6, Quantity = 39, Price = 130.21875})

Update2:可能的错误或功能

仅当fireNewMapEntry为true(GroupBy.cs)时,GroupBy才会触发groupedObservable,这会发生在这里

 if (!_map.TryGetValue(key, out writer))
 {
    writer = new Subject<TElement>();
    _map.Add(key, writer);
    fireNewMapEntry = true;
  }

其中_map的类型为Dictionary<TKey, ISubject<TElement>>。这可能是问题吗?

2 个答案:

答案 0 :(得分:1)

关于你的代码风格的一些注释(对不起,我认为@supertopi已回答它并不是真正的答案)

  1. SubscribeOnObserveOn来电转移到您最终订阅之前的最后一件事。在您当前的代码中,您正在执行Where上的SnoopGroupBy全部_uiScheduler占用宝贵的周期。

  2. 避免在订阅中订阅。看来AddIfNew需要一个密钥和一个IObservable<T>,因此我假设它在内部执行一些订阅。而是依靠你所知道的。如果您正在使用GroupBy,那么您知道在第一次产生组时密钥将是唯一的。所以现在这可以只是一个Add(如果它是你正在检查的键)。如果您想要明确,也可以使用Take(1)。如果值不是您要检查的密钥,那么GroupBy似乎是多余的。

  3. 尝试让变量名称保持一致,因此当另一位开发人员正在阅读查询时,他们会被很好地引导,而不是在subOschildOschildUpdates之间跳转,当childOrder似乎是一个更好的名字(imo)时

  4. 理想情况下,不要在您的可观察序列中返回空值。它有什么用途?在某些罕见的情况下它可能有意义,但我经常发现使用null而不是OnCompleted来表示此序列没有值。

  5. e.g。

    _transportService
            .ObserveSubOrder(parentOrder.OrderId)
            .Where(childOrder => childOrder != null)                
            .Snoop("BeforeGrpBy")
            .GroupBy(childOrder => childOrder.OrderId)
            .SelectMany(grp => grp.Take(1).Select(childOrder=>Tuple.Create(grp.key, childOrder))
            .SubscribeOn(_backgroundScheduler)
            .ObserveOn(_uiScheduler)
            .Subscribe(newGroup =>
            {
                Add(newGroup.Item1, newGroup.Item2);                        
            },
              ex=>//obviously we have error handling here ;-)
            );
    

    _transportService
            .ObserveSubOrder(parentOrder.OrderId)
            .Where(childOrder => childOrder != null)                
            .Snoop("BeforeGrpBy")
            .SubscribeOn(_backgroundScheduler)
            .ObserveOn(_uiScheduler)
            .Subscribe(childOrder =>
              {
                 AddIfNew(childOrder.OrderId, childOrder);                             
              },
              ex=>//obviously we have error handling here ;-)
            );
    

    甚至更好(没有窥探和空检查)

    var subscription = _transportService
            .ObserveSubOrder(parentOrder.OrderId)
            .SubscribeOn(_backgroundScheduler)
            .ObserveOn(_uiScheduler)
            .Subscribe(
              childOrder => AddIfNew(childOrder.OrderId, childOrder),
              ex=>//obviously we have error handling here ;-)
            );
    

    HTH

答案 1 :(得分:0)

您错过了GroupBy的性质。

运营商仅在出现新组后才会发出OnNext(请参阅实施GroupBy.cs:67)。在您的情况下,orderID等于两个通知,因此只会发出一个OnNext

如果您需要访问组内的其他通知,则运营商发出的值为IGroupedObservable<T>,您可以订阅该值。