使用 .NET 反应式扩展时保留对“IDisposable”的引用:始终、从不还是有时?

发布于 2024-10-20 18:58:54 字数 536 浏览 6 评论 0原文

到目前为止,我一直热心地保留对从任何 .Subscribe(...).Connect(...) 返回的 IDisposable 的每个引用> 等 Rx 中的方法。我这样做是因为我担心如果我不保留引用,垃圾收集会处理掉一次性物品。

但是,我在 LINQPad 中进行了测试,在 .Subscribe(...) 上进行了一些调用 GC.Collect() ,但我没有保留引用,并且你猜怎么着?世界并未终结,订阅已完成。

在进一步的测试中,我发现我的订阅在 .OnComplete() 之后立即被销毁,而无需我的干预。

这让我明白,至少对于 .Subscribe(...) 来说,保留对订阅的引用的唯一原因是强制订阅在正常完成之前结束。它更像是取消令牌。

那么所有 Rx 一次性用品都是用于取消而不是用于维持生命吗?

那么,挂起 IDisposable 的规则是什么?

Up until now I have zealously kept every reference to the IDisposable returned from any .Subscribe(...), .Connect(...), etc, method within Rx. I've done this because of my fear that a garbage collections will dispose the disposable if I don't keep the reference.

However, I did a test in LINQPad where I did some calls GC.Collect() on a .Subscribe(...) where I didn't keep the reference and guess what? The world didn't end and the subscription ran to completion.

In further testing I found that my subscription was disposed of immediately after .OnComplete() without my intervention.

This leads me to understand that, at least for .Subscribe(...), that the only reason to keep a reference to the subscription is to force the subscription to end before its normal completion. It's more like a cancellation token.

So are all Rx disposables used for cancelling rather than keeping alive?

What, then, are the rules for hanging on to an IDisposable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

顾挽 2024-10-27 18:58:54

无需保留 IDisposable 对象,除非您想将来取消订阅可观察源。 IScheduler 上的 Schedule 方法类似,其返回的 IDisposable 对象可用于取消计划的操作。

垃圾收集器不直接关心 IDisposable 对象,我们也不在任何对象上实现终结器,因此基本上订阅等的生命周期管理完全取决于 Rx 世界中的您。如果您愿意,请将其与 Win32 句柄进行比较,Dispose 在道德上相当于 CloseHandle。

琐事:在 Rx 设计过程中的某个时刻,可取消操作返回一个 Action,其调用将导致取消。其功能性灵感来自于自然界,但对某些人来说不太明显。因此,我们决定使用一个已经代表资源管理概念的接口,而 IDisposable 是显而易见的选择。也就是说,它与 .NET Framework 中其他地方的接口的典型用法略有不同:

  • 您通常只是将 IDisposable 对象放在地板上,特别是对于您从不取消订阅的无限序列。
  • 在大多数情况下,由于框架固有的异步特性,您不会对 Rx IDisposable 对象使用 using 语句。

希望这会有所帮助,

-Bart(Rx 团队)

No need to hold on to the IDisposable objects unless you want to unsubscribe from an observable source in the future. Similar for the Schedule methods on IScheduler, whose returned IDisposable objects can be used to cancel the scheduled action.

The garbage collector doesn't care about IDisposable object directly, nor do we implement finalizers on any of our objects, so basically lifetime management of subscriptions etc. is entirely up to you in the world of Rx. Compare it to Win32 handles if you want, with Dispose being the moral equivalent to CloseHandle.

Trivia: at some point during the design of Rx, the cancelable operations returned an Action whose invocation would cause the cancellation. Quite functionally inspired in nature, but less obvious to some. So, we decided to go with an interface that already represents a notion of resource management, and IDisposable was the obvious choice. This said, it departs a little from typical usage of the interface elsewhere in the .NET Framework:

  • You'll often just drop the IDisposable object on the floor, in particular for infinite sequences you never unsubscribe from.
  • In most cases, you won't use the using statement for Rx IDisposable objects, due to the inherent asynchronous nature of the framework.

Hope this helps,

-Bart (Rx team)

舂唻埖巳落 2024-10-27 18:58:54

发生之前)时才有用。

IScheduler.Schedule() 返回的 IDisposable 仅当您想要取消计划操作(即, IObservable.Subscribe 返回的 IDisposableIConnectableObservable.Connect 是等效的,因为处理任何一个都会终止对源可观察对象的订阅。

至于垃圾回收,虽然 Rx 让它变得更难以衡量,但它仍然受到 GC 规则的约束。如果您的 observable 的来源是 root 的(如 UI 控件的事件),那么您无需担心它被 GC 处理。

如果您的源是 Observable.Interval 或其他基本上是递归 IScheduler 调用的东西,那么调度程序应该使其保持活动状态(即线程池、任务池或调度程序),因为可观察对象植根于调度程序(通过 IScheduler.Schedule)。

The IDisposable returned by IScheduler.Schedule() is only useful if you want to cancel the scheduled action (that is, before it's happened)

The IDisposable returned by IObservable.Subscribe and IConnectableObservable.Connect are equivalent, in that disposing either will terminate the subscription to the source observable.

As for garbage collection, while Rx makes it a little more difficult to gauge, it's still bound by the rules of the GC. If the source of your observable is rooted (like the event of a UI control), then you don't need to worry about it being GC'd.

If your source is a Observable.Interval or something else is basically a recursive IScheduler call, then the scheduler should keep it alive (ie. the thread pool, task pool, or dispatcher) since the observable is rooted to the scheduler (via IScheduler.Schedule).

謌踐踏愛綪 2024-10-27 18:58:54

好吧,首先我认为重要的是要指出对象的垃圾收集和处置/IDisposable 接口是完全独立的 - 特别是垃圾收集器永远不会通过调用 直接处置对象IDisposable 的 Dispose 方法(除非该对象的终结器本身执行此操作)。

至于何时应该保留 IDisposable,您应该维护对需要处置的任何 IDisposable 对象的引用 - 听起来我正在陈述显而易见的事实那是因为我就是! :-)。除非一次性对象的生命周期比单个方法长,否则通常使用 using 关键字:

using (var myDisposableObject = GetSomeDisposableObject())
{
    myDisposableObject.DoThings();
}

这限制了 myDisposableObject 的范围(这有助于避免尝试使用已被释放的对象)已处置)并确保即使抛出异常也能正确处置该对象。

可能对于某个类/API,您不需要(或不应该)处置返回给您的对象,但这完全取决于该 API/类返回那个一次性物品。

Well, firstly I think its important to point out the garbage collection and disposal of objects / the IDisposable interface are completely separate - in particular the garbage collector will never directly dispose of an object by calling the Dispose method of an IDisposable (unless the finalizer for that object does this itself).

As for when you should hang on to an IDisposable, you should maintain a reference to any IDisposable object that you need to dispose - it sounds like I'm stating the obvious and thats because I am! :-). Unless the disposable objects lifetime is longer than a single method the using keyword is normally used:

using (var myDisposableObject = GetSomeDisposableObject())
{
    myDisposableObject.DoThings();
}

This limits the scope of myDisposableObject (which helps avoid attempting to use an object that has been disposed) and ensures that the object is correctly disposed of even if an exception is thrown.

It may be that for a certain class / API you don't need to (or shouldn't) dispose of an object that is returned to you, however that is entirely up to the API / class that returned that disposable object.

好听的两个字的网名 2024-10-27 18:58:54

是的,从 Subscribe() 返回的 IDisposable 只需要 Unsubscribe() 即可。当然,Unsubscribe() 调用不存在,如果需要,您可以使用 Dispose() 来代替。

Yes, The IDisposable, which is returned from Subscribe() is only needed to Unsubscribe(). Of course, the Unsubscribe() call doesn't exist, you would Dispose() instead, if needed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文