当使用从任务并行库派生的API和类时,开发人员何时需要关注垃圾收集的影响?
Can .NET Task instances go out of scope during run?,似乎给人一种安全感,你不必担心将任务放在范围内。但是问题似乎仅限于在ThreadPool上运行的任务,然后ThreadPool会将它们rooted
。但是,如果我正确理解this MSDN blog post,则该问题的建议通常不适用,因为来自TaskCompletionSource
的任务不同rooted
。
直接使用TaskCompletionSource
是唯一关注的时间吗?
但是,在使用API时,您不知道任务的来源。如果提供的Task
来自TaskCompletionSource
或其他一些非根源,您是否需要担心存储对延续的引用?
从需要考虑任务是否为root(是否同步的异步I / O任务?),这似乎很快变得不方便和复杂。我很难找到关于主题的信息,但它是一个很受欢迎的库,我觉得我不应该阅读反编译的源代码来确定我是否需要担心垃圾收集器的竞争条件,所以我想我必须是遗失或误解了一些东西。
答案 0 :(得分:6)
当您有未完成的TaskCompletionSource
时,总会有两个选项:
将来有可能完成TCS。这意味着某些东西含有对TCS的引用,这意味着它无法获得GC。
正常规则仍然适用于某些内容,因此您可能需要担心保持这种原则。
没有什么能完成那个TCS。这意味着TCS及其任务很快就会得到GC,但是没有工作没有风险(因为没有工作)。
答案 1 :(得分:5)
唯一的问题是Task
是由TaskCompletionSource
提供的,而任何应该利用TaskCompletionSource来设置结果都符合垃圾收集的条件。不幸的是,在这种情况下,API的消费者无法做任何事情,除非他们有权访问并且可以保留对任何内容的引用。因此,对于API实现者的提供者来说,这也是在返回这样的任务时需要注意这一点。
缺乏更好的资源,我不得不通过组合测试(试错)和阅读源代码来确定上述内容。但是,如果没有文档,这些可能是实现细节,可能会在.NET Framework的未来版本中发生变化。
Task
类已被密封,TaskCompletionSource
似乎使用非公共API。因此,排除可能使用非公共API的其他MS API并假设库不反映使用Task
的内部结构,唯一关注的实现是Task
和TaskCompletionSource
。< / p>
除了TaskCompletionSource
创建的内容之外,Task
使用Task
或TaskFactory
上的成员创建Task
。由这些方法之一创建的任何已启动 TaskScheduler
都绑定到TaskScheduler.QueueTask
。由于根据Task-Based Asynchronous Pattern guidelines(excerpt)应该启动任何返回,因此非启动不是消费者需要担心的情况。
根据MSDN上的TaskScheduler
文档(强调我的):
典型的实现将将任务存储在内部数据结构中,这将由将来某个时间执行这些任务的线程提供服务。
因此,只要所使用的TaskScheduler
实现遵循该规则,调度程序就会导致对任务维护引用。只要调度程序使用的数据结构存活,这应该使Task保持活动状态。
框架内置的两个SynchronizationContext
实现在排队任务的存储方面应该是安全的。一个是单例,另一个是TaskScheduler
支持,因此只要上下文存在,排队的任务就会生根。
TaskScheduler
的基本构造函数在静态活动实现列表中注册所有已创建的实例TaskScheduler实例,这可防止任何自定义实现在其他方式可能有资格进行收集时进行垃圾回收。除非TaskScheduler
在排队任务中做了些事情,否则不会出现与自定义{{1}}范围相关的问题。
总的来说,这里没有什么可担心的。
不保证TaskCompletionSources不受任何限制。[1]因此,在设置结果之前,TaskCompletionSource确实存在垃圾收集的可能性。
如果用于确保完成TaskCompletionSource的相关对象是对象的成员,则维护对调用Task-returning方法的对象的引用可能会有所不同。虽然我找不到TAP / TPL的任何指导原则,但应该避免这种情况发生,我希望它们在发生时能够清楚地记录下来。
TaskCompletionSource返回的Task不维护对原始TaskCompletionSource的引用,更不用说引用TaskCompletionSource来设置结果的其他内容了。因此,消费者是否维护对返回的任务的引用不会影响此问题。
在完成所需的对象仅限于任务返回方法的情况下,API使用者实际上无法确保正确性,并且此类情况应被视为提供API中的错误。