【发布时间】:2014-12-06 06:43:06
【问题描述】:
我有一个包含实时数据的流,以及一个基本上划分属于一起的部分实时数据的流。现在,当有人订阅实时数据流时,我想重播他们的实时数据。但是我不想记住所有实时数据,只记住自上次另一个流发出值以来的部分。
There is an issue 这将解决我的问题,因为有一个重播运算符可以完全按照我的意愿(或至少我认为)。
目前有什么方法可以轻松做到这一点?有没有比以下更好的方法?
private class ReplayWithLimitObservable<TItem, TDelimiter> : IConnectableObservable<TItem>
{
private readonly List<TItem> cached = new List<TItem>();
private readonly IObservable<TDelimiter> delimitersObservable;
private readonly IObservable<TItem> itemsObservable;
public ReplayWithLimitObservable(IObservable<TItem> itemsObservable, IObservable<TDelimiter> delimitersObservable)
{
this.itemsObservable = itemsObservable;
this.delimitersObservable = delimitersObservable;
}
public IDisposable Subscribe(IObserver<TItem> observer)
{
lock (cached)
{
cached.ForEach(observer.OnNext);
}
return itemsObservable.Subscribe(observer);
}
public IDisposable Connect()
{
var delimiters = delimitersObservable.Subscribe(
p =>
{
lock (cached)
{
cached.Clear();
}
});
var items = itemsObservable.Subscribe(
p =>
{
lock (cached)
{
cached.Add(p);
}
});
return Disposable.Create(
() =>
{
items.Dispose();
delimiters.Dispose();
lock (cached)
{
cached.Clear();
}
});
}
public static IConnectableObservable<TItem> ReplayWithLimit<TItem, TDelimiter>(IObservable<TItem> items, IObservable<TDelimiter> delimiters)
{
return new ReplayWithLimitObservable<TItem, TDelimiter>(items, delimiters);
}
【问题讨论】:
-
只是一个想法...
ConcurrentBag<T>不是比在cached上使用lock更好的选择吗?我的意思是,这就是它的设计目的...... -
@toadflakz - AFAIK,ConcurrentBag 不保证保留添加顺序(如果可观察的项目行为正确,我会使用列表以正确的顺序获取项目)。 ConcurrentQueue 可以解决这个问题,但清除列表比清除 ConcurrentQueue 更容易。
-
感谢您的解释 - 我对实时数据开发很感兴趣,因此非常感谢有经验的人提供的代码设计决策见解。
-
我同意您的问题代表了框架中的核心限制,您提到的我的工作项目建议向
Replay添加“反应性/反应性”重载可以解决您的问题。 -
在那之前,您的解决方案很好,除了几个问题:1) 永远不要自己实现
IObservable<T>。在这种情况下,您需要一个IConnectableObservable<T>,它比实现自定义主题更快;但是,您仍然应该从ObservableBase<T>派生,以确保自动分离行为、蹦床存在等。 2) 您的Subscribe实现有一个竞争条件,可能会让您错过通知。确保在锁内调用itemsObservable.Subscribe。
标签: c# system.reactive