(译).NET4.X并行任务Task需要释放吗?

传送门:异步编程系列目录……

摘要:本博文解释在.NET 4.X中的Task使用完后为什么不应该调用Dispose()。并且说明.NET4.5对.NET4.0的Task对象进行的部分改进:减轻Task对WaitHandle对象的依赖,并且增强在释放了Task后对其成员的可访问性。

我多次获得这样一个问题:

“Task实现了IDisposable接口并且公开Dispose()方法,这是否意味着我们要对所有的任务进行释放吗?”

概述

  1. 这是我对该问题的简要回答:

“不是,不用释放你持有的Task。”

  1. 这是我对该问题的中篇回答:

“不是,不用释放你持有的Task,除非性能报告或可伸缩性测试报告显示你需要释放Task以满足你的性能目标。如果你发现一个需要被释放的Task,必须100%确保在你的释放点处该Task已经完成并且没有被其他地方在使用。”

  1. 下面,你可以找一个休闲的阅读时间,这是我对该问题的长回答:

为什么要调用Task的Dispose()?

.NET Framework设计指南中指出:一个类型如果持有其它实现过IDisposable接口的资源时,其自身也应该实现IDisposable接口。在Task内部,可能会分配一个WaitHandle对象用于等待任务完成。WaitHandle实现IDisposable接口因为它持有SafeWaitHandle内核等待句柄,所以Task实现了IDisposable接口。如果不主动释放SafeWaitHandle句柄,最终终结器也会将其清理,但是不能对此资源立即清理并且还将此清理工作负荷遗留给系统。通过给Task实现IDisposable接口,我们可以让开发人员能主动及时的对资源进行释放。

问题

如果为每一个Task都分配一个WaitHandle,那么释放Task将是一个好措施因为这样能提高性能。但是事实并非如此,现实中,为Task分配WaitHandle的情况是非常少出现的。在.NET 4.0中,WaitHandle在以下几种情况会延迟初始化:访问 ((IAsyncResult)task).AsyncWaitHandle成员,或者调用Task的WaitAll()/WaitAny()方法(这两个方法在.NET4.0版本中,内部是基于Task的WaitHandle对象实现的)。这使得回答“是否应该释放Task”问题更加困难了,因为如果Task都使用了WaitAll()/WaitAny(),那么释放Task就是一个好选择。

?
1
2
3
4
5
6
7
public interface IAsyncResult
{
    object AsyncState { get; }
    WaitHandle AsyncWaitHandle { get; }
    bool CompletedSynchronously { get; }
    bool IsCompleted { get; }
}

在.NET 4.0中,一个Task一旦被释放,它的大多数成员访问都会抛出ObjectDisposedExceptions异常。这使得完成的任务很难被安全的缓存,因为一个消费者释放Task后,另一个消费者无法再访问Task的一些重要成员,如ContinueWith()方法或Result属性。

这里还有另外一个问题:Task是基础同步基元。如果Task被用于并行化,如在一个fork/join模式(”分支/合并”模式)中那么它就很容易知道什么时候完成它们和什么时候没有人再使用它们,比如:

?
1
2
3
4
5
6
var tasks = new Task[3];
tasks[0] = Compute1Async();
tasks[1] = Compute2Async();
tasks[2] = Compute3Async();
Task.WaitAll(tasks);
foreach(var task in tasks) task.Dispose();

然而,当使用Task的延续任务时,就很难判断它什么时候完成它们和什么时候没有人再使用它们,比如:

?
1
2
3
4
5
Compute1Async().ContinueWith(t1 =>
{
    t1.Dispose();
    
});

示例成功的释放掉Compute1Async()返回的Task,但是它忽略了如何释放ContinueWith()返回的Task。当然,我们能使用同样的方法释放这个Task。

?
1
2
3
4
5
Compute1Async().ContinueWith(t1 =>
{
    t1.Dispose();
    
}).ContinueWith(t2 => t2.Dispose());

但是我们不能释放第二个ContinueWith()返回的Task。即使使用C#5.0中新的async/await异步方法也不能解决。例如:

?
1
2
3
string s1 = await Compute1Async();
string s2 = await Compute2Async(s1);
string s3 = await Compute3Async(s2);

如果想释放这些Task,我需要进行像下面这样的重写:

?
1
2
3
4
5
6
7
string s1 = null, s2 = null, s3 = null;
using(var t1 = Compute1Async())
    s1 = await t1;
using(var t2 = Compute2Async(s1))
    s2 = await t2;
using(var t3 = Compute3Async(s2))
    s3 = await t3;

解决方案

由于像上面这样进行释放大多数Task显得很繁琐,所以在.NET4.5中已经对Task的Dispose()做过一些改进:

  1. 我们使得你更少机会为Task创建WaitHandle对象。在.NET4.5中我们已经重写了Task的WaitAll()和WaitAny()以致这两个方法不再依赖与WaitHandle对象(这样WaitAll()、WaitAny()、Wait()就都基于自旋等待),避免在Task的内部实现中使用WaitHandle对象,并且提供async/await相关异步功能。因此,只有当你显示访问Task的IAsyncResult.AsyncWaitHandle成员才会为Task分配WaitHandle对象,但这种需求非常少见。这意味着除了这种非常少见的情况外,释放一个任务是不需要的。
  2. 我们使得Task在释放后依然可用。你能使用Task的所有公开成员即使Task已经被释放,访问这些成员的表现就和释放Task之前一样。只有IAsyncResult.AsyncWaitHandle成员你不能使用,因为这是你释放Task时真真所释放的对象,当你尝试在释放Task后访问这个属性时依然会抛出ObjectDisposedException。此外,更进一步的说,现在我们推荐使用async/await异步方法以及基于任务的异步编程模式,降低对IAsyncResult的使用,即使你继续使用((IAsyncResult)task),调用其AsyncWaitHandle成员也是十分罕见的。
  3. Task.Dispose()方法在“.NET Metro风格应用程序”框架所引用的程序集中甚至并不存在(即此框架中Task没有实现IDisposable接口)。

指南

所以,这又让我们回到了简要的回答:“不是,不用释放你的Task。”通常很难找到一个合适的释放点,目前几乎没有一个理由需要去主动释放Task(因为调用((IAsyncResult)task).AsyncWaitHandle成员的需求是十分罕见的),并且在“.NET Metro风格应用程序”框架所引用的程序集中你甚至不能调用Task的Dispose()方法。

更多资源来源博文:关于Async与Await的FAQ

原文:http://blogs.msdn.com/b/pfxteam/archive/2012/03/25/10287435.aspx

作者:Stephen Toub - MSFT

转载于:https://www.cnblogs.com/changbaishan/p/4624514.html

(译).NET4.X并行任务Task需要释放吗?相关推荐

  1. 【转】1.B(译).NET4.X并行任务Task需要释放吗?

    传送门:异步编程系列目录-- 摘要:本博文解释在.NET 4.X中的Task使用完后为什么不应该调用Dispose().并且说明.NET4.5对.NET4.0的Task对象进行的部分改进:减轻Task ...

  2. 【转】1.A(译).NET4.X 并行任务中Task.Start()的FAQ

    传送门:异步编程系列目录-- 近期有不少人向我咨询关于Task的Start()方法.比如:何时使用及何时不使用Start().Start()又做了些什么--我想在这里回答一些问题试图澄清和平息任何关于 ...

  3. .Net4.0 任务(Task)

    任务(Task)是一个管理并行工作单元的轻量级对象.它通过使用CLR的线程池来避免启动专用线程,可以更有效率的利用线程池.System.Threading.Tasks 命名空间下任务相关类一览: 类 ...

  4. 【转】异步编程系列(Thread、Task、async/await、ajax等)

    序 经过一番努力,我写的异步编程系列也算有头有尾,当然不是说这个系列已经更新完毕,这个头尾只是表示新旧知识点都有简单涉及到,接下去我还会丰富这一系列并且有机会整个小应用(愿景是弄一个开源组件吧,结合s ...

  5. 【转】2.1(译)关于async与await的FAQ

    传送门:异步编程系列目录-- 环境:VS2012(尽管System.Threading.Tasks在.net4.0就引入,在.net4.5中为其增加了更丰富的API及性能提升,另外关键字"a ...

  6. 关于async与await的FAQ 转

    (译)关于async与await的FAQ 传送门:异步编程系列目录-- 环境:VS2012(尽管System.Threading.Tasks在.net4.0就引入,在.net4.5中为其增加了更丰富的 ...

  7. 【转】异步编程:.NET 4.5 基于任务的异步编程模型(TAP)

    最近我为大家陆续介绍了"IAsyncResult异步编程模型 (APM)"和"基于事件的异步编程模式(EAP)"两种异步编程模型.在.NET4.0 中Micro ...

  8. 【转】1.8异步编程:.NET 4.5 基于任务的异步编程模型(TAP)

    传送门:异步编程系列目录-- 最近我为大家陆续介绍了"IAsyncResult异步编程模型 (APM)"和"基于事件的异步编程模式(EAP)"两种异步编程模型. ...

  9. 《C#本质论》读书笔记(18)多线程处理

    .NET Framework 4.0 看(本质论第3版) .NET Framework 4.5 看(本质论第4版) .NET 4.0为多线程引入了两组新API:TPL(Task Parallel Li ...

  10. 【转】3.7(译)构建Async同步基元,Part 7 AsyncReaderWriterLock

    传送门:异步编程系列目录-- 最近在学习.NET4.5关于"并行任务"的使用."并行任务"有自己的同步机制,没有显示给出类似如旧版本的:事件等待句柄.信号量.l ...

最新文章

  1. Leetcode1689. 十-二进制数的最少数目[C++题解]:贪心、找规律简单题
  2. 35 CO配置-控制-产品成本控制-成本对象控制-期末结算-定义在产品和废品的评估变式 (目标成本)
  3. Android 推断当前Activity是不是最后一个Activity 以及 应用或Activity是否存在
  4. popoupwindow 点击背景消失_两种去除背景音乐保留原声的高效方法
  5. cocos2dx 3.16 VS+BabeLua lua环境配置与代码调试
  6. autoload.php beanbun_PHP爬虫框架Beanbun使用
  7. 微信支付全部详细流程
  8. UPnP 端口映射服务威胁分析
  9. wget:Unable to establish SSL connection错误
  10. flutter A problem occurred configuring project ‘:shared_preferences_linux‘.
  11. tp6 gatewayWorker
  12. 模电_安规X电容_Y电容-区别与作用-20190507
  13. C# 使用SharpGL-Perspective和LookAt
  14. 微信小程序使用 ECharts
  15. 网易七鱼“大闹”客服行业,真能一举定乾坤?
  16. Markdown 更改字体颜色
  17. 同步,异步的定义和区别
  18. 【自然语言处理】Word2Vec 词向量模型详解 + Python代码实战
  19. Intellij Idea远程调试小记
  20. php中car是什么意思,car是什么意思_car在线翻译_英语_读音_用法_例句_海词词典

热门文章

  1. VC使用命令行编译很复杂
  2. 能韬光养晦,是因为面前有苏联顶着,苏联没了就不可能了
  3. 缓冲区提前释放,导致H264保存及播放错误
  4. NWT失败反思:公司都死了,还怕得罪人
  5. java lambda 原理_Java Lambda表达式原理及多线程实现
  6. latex 调整表格的行高_latex 表格如何控制行高,行距,行与行之间的距离
  7. linux 开机自动运行命令_Linux内核分析-启动顺序、运行级别及开机启动(七)
  8. mysql资源限制_超出了MariaDB / MySQL资源限制
  9. office2010 反应慢_office2010打开时间太慢。怎么办?
  10. axure轮播图怎么设置循环轮播_Axure RP8 动态面板之轮播图设置