唯一需要担心的是,当Task
由 a 提供时TaskCompletionSource
,应该使用 TaskCompletionSource 来设置结果的任何东西都有资格进行垃圾收集。不幸的是,API 的使用者在这种情况下无能为力,除非他们有权访问并持有对任何内容的引用。因此,这也是 API 实现者的提供者在返回此类任务时需要注意这一点的问题。
由于缺乏更好的资源,我不得不通过结合测试(试错)和阅读源代码来确定上述情况。但是,在没有文档的情况下,这些可能是实现细节,并且可能会在 .NET Framework 的未来版本中发生变化。
进一步说明
该类Task
是密封的,并且似乎TaskCompletionSource
可以通过使用非公共 API 来工作。因此,排除可能使用非公共 API 的其他 MS API 并假设库没有反射性地使用Task
的内部结构,唯一需要关注的实现是Task
和TaskCompletionSource
。
任务(不是来自 TaskCompletionSource)
除了由TaskCompletionSource
,创建的那些之外,是使用或Task
上的成员创建的。由这两种方法中的任何一种创建的任何启动都绑定到. 由于根据基于任务的异步模式指南(摘录),任何返回的任务都应该启动,因此消费者不需要担心未启动的情况。Task
TaskFactory
Task
TaskScheduler
根据TaskScheduler.QueueTask
MSDN 上的文档(强调我的):
一个典型的实现会将任务存储在一个内部数据结构中,该结构将由将来某个时间执行这些任务的线程提供服务。
因此,只要使用的TaskScheduler
实现遵守这一点,调度程序就会导致对任务的引用保持。只要调度程序使用的数据结构处于活动状态,这应该使任务保持活动状态。
TaskScheduler
框架中内置的两个实现对于队列任务的存储应该是安全的。一个是单例,另一个由 支持,SynchronizationContext
因此只要上下文存在,排队的任务就会被植根。
用于在活动实现的静态列表中注册所有创建的 TaskScheduler 实例的基本构造函数TaskScheduler
,这应该防止任何自定义实现在可能有资格被收集时被垃圾收集。不应该出现与 customTaskScheduler
的范围相关的问题,除非TaskScheduler
它在排队任务中做一些不合时宜的事情。
总的来说,这里没有什么可担心的。
任务完成源
TaskCompletionSources 不能保证以任何东西为根。[1]因此,TaskCompletionSource 确实存在在设置结果之前被垃圾收集的可能性。
如果用于确保 TaskCompletionSource 完成的相关对象是对象的成员,则维护对调用 Task-returning 方法的对象的引用可能会有所不同。虽然我找不到任何关于 TAP/TPL 的指南来避免这种情况,但我希望它们在发生时被清楚地记录在案。
TaskCompletionSource 返回的 Task 不维护对原始 TaskCompletionSource 的引用,更不用说任何其他应该引用 TaskCompletionSource 来设置结果的内容。所以消费者是否维护了对返回任务的引用不影响这个问题。
在完成所需的对象仅限于任务返回方法的情况下,API 使用者实际上无法确保正确性,这种情况应被视为提供 API 中的错误。