我想触发任务在后台线程上运行。我不想等待任务完成。
在.net 3.5中,我应该这样做:
ThreadPool.QueueUserWorkItem(d => { DoSomething(); });
在.net 4中,建议使用TPL。我看到的推荐的常见模式是:
Task.Factory.StartNew(() => { DoSomething(); });
但是,该StartNew()方法返回一个Task实现的对象IDisposable。推荐这种模式的人似乎忽略了这一点。有关该Task.Dispose()方法的MSDN文档说:
StartNew()
Task
IDisposable
Task.Dispose()
“在释放对任务的最后引用之前,请始终致电Dispose。”
您不能在任务完成之前对其进行调用处置,因此首先让主线程等待并进行调用处置会破坏在后台线程上执行任务的目的。似乎也没有任何可用于清除的完成/完成事件。
Task类上的MSDN页面对此没有评论,而书“ Pro C#2010 …”推荐了相同的模式,并且对任务处理没有评论。
我知道我是否只保留它,终结器最终会抓住它,但是当我做很多工作而忘了像这样的任务而终结器线程不堪重负时,这又会回来咬我吗?
所以我的问题是:
Dispose()
MSDN论坛中对此进行了讨论。
Microsoft pfx团队的成员Stephen Toub这样说:
Task.Dispose之所以存在,是因为Task可能包装了在等待任务完成时使用的事件句柄,以防等待线程实际上不得不阻塞(而不是旋转或潜在地执行其正在等待的任务)。如果您所做的只是使用延续,那么该事件句柄将永远不会被分配 … 最好依靠终结来处理事情。
更新(2012年10月) Stephen Toub发布了一个博客,标题为“我需要处理任务吗?其中提供了更多详细信息,并说明了.Net 4.5中的改进。
总结:您不需要Task99%的时间处理对象。
放置对象的主要原因有两个:以及时,确定的方式释放不受管理的资源,以及避免运行对象的终结器的成本。这些都不适用于Task大多数时间:
IAsyncResult.AsyncWaitHandle