这可能是一个非常愚蠢的问题,但我不确定我是否应该继续使用Linq扩展方法生成的IObservable。默认情况下,大多数示例似乎都这样做,但在长时间运行的程序中会发生什么。我有两个例子来解释我的问题:
我的第一个,也是当前的默认实现,涉及订阅pub \ sub事件聚合器提供的IObservable。我对此很满意,因为我知道只要聚合器是可观察的,就会存在。
protected virtual void SubscribeToEvents()
{
_subscriptions.Dispose();
_subscriptions = new CompositeDisposable();
IDisposable sendSubscription = Events.GetStream<OutgoingByteMessage>()
.Subscribe(msg =>
{
if (msg.Identifier.ChannelId == this.Id)
{
var queueItem = Tuple.Create(msg.Identifier.ConnectionId, msg.Data);
_sendQueue.Enqueue(queueItem);
}
});
_subscriptions.Add(sendSubscription);
}
但是,如果我使用Linq来打破某些逻辑,我可以这样做以获得订阅:
IDisposable altSendSubscription = Events.GetStream<OutgoingByteMessage>()
.Where(msg => msg.Identifier.ChannelId == this.Id)
.Select(msg => Tuple.Create(msg.Identifier.ConnectionId, msg.Data))
.Subscribe(item =>
{
_sendQueue.Enqueue(item);
});
我的问题是,在第二个版本上,我应该保留那个.Select方法的产品吗?这种情况在一个方法中发生,毕竟在技术上不会返回那里的订单,只要SubscribeToEvents完成并且有资格进行垃圾收集,它就会超出范围?或者IDisposable对象本身是否保留对它的引用,从而使得在某处不能保留对它的具体引用是安全的。
在查看Rx源之后,看起来他们使用一系列转发器类来完成Linq魔术,但我仍然有点偏执。你们觉得怎么样?
答案 0 :(得分:3)
在一天结束时,所有IObservable对象都通过Events.GetStream
上的订阅者列表保留(当然,取决于您Events.GetStream
的实现)。这是否超出范围取决于您的实施。
但是,持有IDisposable
几乎肯定会将订阅保留在范围内,因此,即使您的实施是return Observable.Never<OutgoingByteMessage>
,由于IDisposable
,它仍然存在。
您通常不必担心活动订阅超出范围 - 您应该担心的是订阅泄漏。当您订阅全局对象(例如从IoC容器返回的内容)并且不断开订阅时(如果Observable永远不会终止),就会发生这些情况。
这听起来似乎不经常发生,但它的出现超出了你的期望。例如:
MessageBus.Current.Listen<FooMessage>()
.Where(x => x.Bar == "Baz")
.Subscribe(x => Console.WriteLine(x));
如果我把它放在一个始终创建的对象的构造函数中,我会创建许多永远不会被清理的订阅。
答案 1 :(得分:2)
您甚至不需要保留订阅句柄(altSendSubscription
)。
为什么不使用内存分析器并查看堆来说服自己?