我有一个问题,我不知道如何处理与RX精美。 我有多个流,所有这些都应该包含相同的元素 但是,与其他人相比,每个流可能会丢失消息(涉及UDP)或迟到/早。这些消息中的每一条都有一个序列号。
现在我想要实现的是从所有这些流中获取单个流,没有重复并保持消息顺序。换句话说,相同的序列号不应出现两次,它们的值只需要增加,不要减少。 当消息在所有流上丢失时,我可以丢失它(因为涉及的另一个TCP机制允许我明确询问丢失的消息)。
我希望在RxJava中这样做,但我想我的问题不是特定于Java。
这是一张大理石图,可帮助我看到我想要实现的目标: marble diagram
您可以在该图表中看到我们正在等待第一个流上的 2 从第二个流输出 3 。 同样,只有在我们从第二个流收到 6 时才输出 6 ,因为只有在那时我们才能确定 5 永远不会被任何流收到。
答案 0 :(得分:2)
这是浏览器代码,但我认为它应该让你很好地了解如何解决这个问题。
public static IObservable<T> Sequenced<T>(
this IObservable<T> source,
Func<T, int> getSequenceNumber,
int sequenceBegin,
int sequenceRedundancy)
{
return Observable.Create(observer =>
{
// The next sequence number in order.
var sequenceNext = sequenceBegin;
// The key is the sequence number.
// The value is (T, Count).
var counts = new SortedDictionary<int, Tuple<T, int>>();
return source.Subscribe(
value =>
{
var sequenceNumber = getSequenceNumber(value);
// If the sequence number for the current value is
// earlier in the sequence, just throw away this value.
if (sequenceNumber < sequenceNext)
{
return;
}
// Update counts based on the current value.
Tuple<T, int> count;
if (!counts.TryGetValue(sequenceNumber, out count))
{
count = Tuple.Create(value, 0);
}
count = Tuple.Create(count.Item1, count.Item2 + 1);
counts[sequenceNumber] = count;
// If the current count has reached sequenceRedundancy,
// that means any seqeunce values S such that
// sequenceNext < S < sequenceNumber and S has not been
// seen yet will never be seen. So we emit everything
// we have seen up to this point, in order.
if (count.Item2 >= sequenceRedundancy)
{
var removal = counts.Keys
.TakeWhile(seq => seq <= sequenceNumber)
.ToList();
foreach (var seq in removal)
{
count = counts[seq];
observer.OnNext(count.Item1);
counts.Remove(seq);
}
sequenceNext++;
}
// Emit stored values as long as we keep having the
// next sequence value.
while (counts.TryGetValue(sequenceNext, out count))
{
observer.OnNext(count.Item1);
counts.Remove(sequenceNext);
sequenceNext++;
}
},
observer.OnError,
() =>
{
// Emit in order any remaining values.
foreach (var count in counts.Values)
{
observer.OnNext(count.Item1);
}
observer.OnCompleted();
});
});
}
如果您有两个流IObservable<Message> A
和IObservable<Message> B
,则可以通过执行Observable.Merge(A, B).Sequenced(msg => msg.SequenceNumber, 1, 2)
来使用此流。
对于示例大理石图,这将如下所示,其中source
列显示Observable.Merge(A, B)
发出的值,counts
列显示{{1}的内容在算法的每个步骤之后。我假设原始源序列的“消息”(没有任何丢失的值)是(A,1),(B,2),(C,3),(D,4),(E,5), (F,6)其中每条消息的第二个组成部分是其序列号。
SortedDictionary
答案 1 :(得分:0)
前一段时间出现了类似的问题I have a custom merge operator,当给定有序流时,它会按顺序合并它们,但不会进行重复数据删除。
修改强>
如果你“负担得起”它,你可以使用这个自定义合并,然后使用distinctUntilChanged(Func1)
来过滤掉具有相同序列号的后续消息。
Observable<Message> messages = SortedMerge.create(
Arrays.asList(src1, src2, src3), (a, b) -> Long.compare(a.id, b.id))
.distinctUntilChanged(v -> v.id);