如何定期合并observable?

时间:2015-01-29 04:40:25

标签: c# system.reactive

我正在尝试定期合并两个传感器数据流,而我在Rx中无法正常执行此操作。我提出的最好的是下面的示例,但我怀疑这是Rx的最佳使用。

有更好的方法吗?

我尝试了Sample(),但传感器以不规则的间隔,慢(> 1秒)和快(<1秒)产生值。 Sample()似乎只处理快速数据。

Observable<SensorA> sensorA = ... /* hot */
Observable<SensorB> sensorB = ... /* hot */

SensorA lastKnownSensorA;
SensorB lastKnownSensorB;

sensorA.Subscribe(s => lastKnownSensorA = s);
sensorB.Subscribe(s => lastKnownSensorB = s);

var combined = Observable.Interval(TimeSpan.FromSeconds(1))
    .Where(t => _lastKnownSensorA != null)
    .Select(t => new SensorAB(lastKnownSensorA, lastKnownSensorB)

2 个答案:

答案 0 :(得分:4)

我认为@JonasChapuis的答案可能就是你所追求的,但有几个问题可能会有问题:

  • CombineLatest在所有源都发出至少一个值之前不会发出值,这可能会导致从更快的源中丢失数据直到该点。可以使用StartWith在每个传感器流上播种null object或默认值来减轻这种情况。

  • 如果在样本期间未观察到新值,则
  • Sample将不会发出值。我无法从这个问题中判断出这是否可取,但如果没有,那就有一个有趣的诀窍来解决这个问题,使用&#34; pace&#34;流,如下所述创建固定频率,而不是Sample获得的最大频率。

要解决CombineLatest问题,请为传感器流确定适当的空值 - 我通常通过类型上的静态Null属性使这些值可用 - 这使得意图非常明确。对于值类型,使用Nullable<T>也是一个不错的选择:

Observable<SensorA> sensorA = ...  .StartWith(SensorA.Null);
Observable<SensorB> sensorB = ...  .StartWith(SensorB.Null);

N.B。不要将StartWith仅应用于CombinedLatest ...的输出,而这不会导致帮助!

现在,如果您需要定期结果(自然可能包括最近读数的重复),请创建一个&#34;步伐&#34;以所需间隔发出的流:

var pace = Observable.Interval(TimeSpan.FromSeconds(1));

然后按如下方式组合,省略结果中的步速值:

var sensorReadings = Observable.CombineLatest(
    pace, sensorA, sensorB,
    (_, a, b) => new SensorAB(a,b));

如果您想以特定流的速度推动输出,那么还非常有效地了解MostRecent运算符,它可以非常有效地与Zip结合使用。请参阅这些答案,我演示了这种方法:How to combine a slow moving observable with the most recent value of a fast moving observable以及处理多个流的更有趣的调整:How do I combine three observables such that

答案 1 :(得分:2)

每次使用CombineLatest()运算符合并传感器的最新值时,如何生成值,然后Sample()以确保每秒一次测量的最大频率?

sensorA.CombineLatest(sensorB, (a, b) => new {A=a, B=b}).Sample(TimeSpan.FromSeconds(1))