13

开发人员在使用派生自任务并行库的 API 和类时,何时需要关注垃圾回收的影响?

.NET Task 实例可以在运行期间超出范围吗?,似乎会给您一种安全感,您不必担心将任务保持在范围内。但是,问题似乎仅限于在 ThreadPool 上运行的任务,然后它们rooted由 ThreadPool 运行。但是,如果我正确理解了这篇 MSDN 博客文章,那么来自该 SO 问题的建议并不普遍适用,因为来自TaskCompletionSource的任务并不相似rooted

是不是直接使用TaskCompletionSource时才值得关注?
但是,在使用 API 时,您不知道 Task 来自何处。然后,您是否需要担心存储对延续的引用,以防提供的内容Task来自某个TaskCompletionSource或其他非根源?

由于需要考虑任务是否已植根(异步 I/O 任务是否植根?),这似乎很快变得不方便和复杂。我正在努力寻找有关该主题的大量信息,但它是一个足够流行的库遗漏或误解某事。

4

2 回答 2

8

当你有 uncompletedTaskCompletionSource时,总是有两种选择:

  1. 将来可能会完成该 TCS。这意味着某个东西持有对 TCS 的引用,这意味着它不能被 GCed。

    正常的规则仍然适用于那个东西,所以你可能需要担心保持它的根。

  2. 没有什么可以完成该 TCS。这意味着 TCS 及其任务可能很快就会获得 GCed,但不存在工作未完成的风险(因为没有工作)。

于 2013-08-06T22:44:24.090 回答
6

唯一需要担心的是,当Task由 a 提供时TaskCompletionSource,应该使用 TaskCompletionSource 来设置结果的任何东西都有资格进行垃圾收集。不幸的是,API 的使用者在这种情况下无能为力,除非他们有权访问并持有对任何内容的引用。因此,这也是 API 实现者的提供者在返回此类任务时需要注意这一点的问题。

由于缺乏更好的资源,我不得不通过结合测试(试错)和阅读源代码来确定上述情况。但是,在没有文档的情况下,这些可能是实现细节,并且可能会在 .NET Framework 的未来版本中发生变化。

进一步说明

该类Task是密封的,并且似乎TaskCompletionSource可以通过使用非公共 API 来工作。因此,排除可能使用非公共 API 的其他 MS API 并假设库没有反射性地使用Task的内部结构,唯一需要关注的实现是TaskTaskCompletionSource

任务(不是来自 TaskCompletionSource)

除了由TaskCompletionSource,创建的那些之外,是使用或Task上的成员创建的。由这两种方法中的任何一种创建的任何启动都绑定到. 由于根据基于任务的异步模式指南(摘录),任何返回的任务都应该启动,因此消费者不需要担心未启动的情况。TaskTaskFactory TaskTaskScheduler

根据TaskScheduler.QueueTaskMSDN 上的文档(强调我的):

一个典型的实现会将任务存储在一个内部数据结构中,该结构将由将来某个时间执行这些任务的线程提供服务。

因此,只要使用的TaskScheduler实现遵守这一点,调度程序就会导致对任务的引用保持。只要调度程序使用的数据结构处于活动状态,这应该使任务保持活动状态。

TaskScheduler框架中内置的两个实现对于队列任务的存储应该是安全的。一个是单例,另一个由 支持,SynchronizationContext因此只要上下文存在,排队的任务就会被植根。

用于在活动实现的静态列表中注册所有创建的 TaskScheduler 实例的基本构造函数TaskScheduler,这应该防止任何自定义实现在可能有资格被收集时被垃圾收集。不应该出现与 customTaskScheduler的范围相关的问题,除非TaskScheduler它在排队任务中做一些不合时宜的事情。

总的来说,这里没有什么可担心的。

任务完成源

TaskCompletionSources 不能保证以任何东西为根。[1]因此,TaskCompletionSource 确实存在在设置结果之前被垃圾收集的可能性。

如果用于确保 TaskCompletionSource 完成的相关对象是对象的成员,则维护对调用 Task-returning 方法的对象的引用可能会有所不同。虽然我找不到任何关于 TAP/TPL 的指南来避免这种情况,但我希望它们在发生时被清楚地记录在案。

TaskCompletionSource 返回的 Task 不维护对原始 TaskCompletionSource 的引用,更不用说任何其他应该引用 TaskCompletionSource 来设置结果的内容。所以消费者是否维护了对返回任务的引用不影响这个问题。

在完成所需的对象仅限于任务返回方法的情况下,API 使用者实际上无法确保正确性,这种情况应被视为提供 API 中的错误。

于 2013-08-07T20:26:45.083 回答