Sim*_*ens 117 .net c# multithreading dispose task-parallel-library
我想触发一个在后台线程上运行的任务.我不想等待任务完成.
在.net 3.5中,我会这样做:
ThreadPool.QueueUserWorkItem(d => { DoSomething(); });
Run Code Online (Sandbox Code Playgroud)
在.net 4中,TPL是建议的方式.我见过的常见模式是:
Task.Factory.StartNew(() => { DoSomething(); });
Run Code Online (Sandbox Code Playgroud)
但是,该StartNew()
方法返回一个Task
实现的对象IDisposable
.推荐这种模式的人似乎忽视了这一点.有关该Task.Dispose()
方法的MSDN文档说:
"在释放对任务的最后一个引用之前,始终调用Dispose."
你不能在任务完成之前调用dispose,所以让主线程等待并调用dispose会首先打破后台线程上的操作.似乎也没有任何已完成/已完成的事件可用于清理.
Task类上的MSDN页面没有对此进行评论,并且"Pro C#2010 ..."一书推荐了相同的模式,并且没有对任务处理做出评论.
我知道如果我离开它,终结者最终会抓住它,但当我做了大量的火灾并且忘记了这样的任务并且终结者线程被淹没时,它会回来咬我吗?
所以我的问题是:
Dispose()
就Task
在这种情况下类?如果是这样,为什么会有风险/后果?Task
我错过的物体?Kir*_*kov 102
微软pfx团队成员Stephen Toub对此说:
Task.Dispose存在是由于Task可能包装在等待任务完成时使用的事件句柄,如果等待线程实际上必须阻塞(而不是旋转或可能正在执行它正在等待的任务).如果您所做的只是使用continuation,那么永远不会分配该事件句柄
......
最好依靠finalization来处理事情.
更新(2012年10月)
Stephen Toub发布了一个名为"我是否需要处理任务? "的博客?它提供了更多细节,并解释了.Net 4.5的改进.
总结:您不需要Task
99%的时间处置对象.
处理对象有两个主要原因:以及时,确定的方式释放非托管资源,并避免运行对象的终结器的成本.这些都不适用于Task
大多数时间:
Task
分配的内部等待句柄(中唯一的非托管资源Task
对象)时,明确使用IAsyncResult.AsyncWaitHandle
的Task
,并Task
对象本身没有终结; 句柄本身用一个终结器包裹在一个对象中,所以除非它被分配,否则没有终结器可以运行.Han*_*ant 14
这与Thread类相同.它消耗5个操作系统句柄但不实现IDisposable.原始设计师的好决定,当然有几种合理的方法来调用Dispose()方法.你必须先调用Join().
Task类为此添加一个句柄,即内部手动重置事件.哪个是最便宜的操作系统资源.当然,它的Dispose()方法只能释放一个事件句柄,而不是Thread消耗的5个句柄. 是的,不要打扰.
请注意,您应该对任务的IsFaulted属性感兴趣.这是一个相当丑陋的话题,你可以在这篇MSDN Library文章中阅读更多相关内容.一旦你正确处理了这个问题,你也应该在你的代码中有一个很好的位置来处理这些任务.
归档时间: |
|
查看次数: |
24353 次 |
最近记录: |