NET4.X并行任务c task 并行需要释放吗

摘要:本博文解释在.NET 4.X中的Task使用完后为什么不应该调用Dispose()。并且说明.NET4.5对.NET4.0的Task对象进行的部分改进:减轻Task对WaitHandle对象的依赖,并且增强在释放了Task后对其成员的可访问性。
我多次获得这样一个问题:
&&&&&&&& “Task实现了IDisposable接口并且公开Dispose()方法,这是否意味着我们要对所有的任务进行释放吗?”
1.这是我对该问题的简要回答:
“不是,不用释放你持有的Task。”
2.这是我对该问题的中篇回答:
“不是,不用释放你持有的Task,除非性能报告或可伸缩性测试报告显示你需要释放Task以满足你的性能目标。如果你发现一个需要被释放的Task,必须100%确保在你的释放点处该Task已经完成并且没有被其他地方在使用。”
3.下面,你可以找一个休闲的阅读时间,这是我对该问题的长回答:
为什么要调用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就是一个好选择。
public interface IAsyncResult
object AsyncState { }
WaitHandle AsyncWaitHandle { }
bool CompletedSynchronously { }
bool IsCompleted { }
&&&&&&&& 在.NET 4.0中,一个Task一旦被释放,它的大多数成员访问都会抛出ObjectDisposedExceptions异常。这使得完成的任务很难被安全的缓存,因为一个消费者释放Task后,另一个消费者无法再访问Task的一些重要成员,如ContinueWith()方法或Result属性。
&&&&&&&& 这里还有另外一个问题:Task是基础同步基元。如果Task被用于并行化,如在一个fork/join模式(”分支/合并”模式)中那么它就很容易知道什么时候完成它们和什么时候没有人再使用它们,比如:
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的延续任务时,就很难判断它什么时候完成它们和什么时候没有人再使用它们,比如:
Compute1Async().ContinueWith(t1 =&
t1.Dispose();
示例成功的释放掉Compute1Async()返回的Task,但是它忽略了如何释放ContinueWith()返回的Task。当然,我们能使用同样的方法释放这个Task。
Compute1Async().ContinueWith(t1 =&
t1.Dispose();
}).ContinueWith(t2 =& t2.Dispose());
但是我们不能释放第二个ContinueWith()返回的Task。即使使用C#5.0中新的async/await异步方法也不能解决。例如:
string s1 = await Compute1Async();
string s2 = await Compute2Async(s1);
string s3 = await Compute3Async(s2);
如果想释放这些Task,我需要进行像下面这样的重写:
string s1 = null, s2 = null, s3 =
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()方法。&
&&&&&&&&&&&&&&&&&&&
更多资源来源博文:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:6497129次
积分:73093
积分:73093
排名:第13名
原创:435篇
转载:4678篇
译文:22篇
评论:1580条
文章:21篇
阅读:41070
文章:15篇
阅读:31072
文章:22篇
阅读:192657
(4)(8)(28)(21)(47)(1)(1)(8)(170)(814)(1012)(1351)(969)(262)(207)(2)(3)(2)(61)(19)(2)(28)(22)(37)(1)(3)(4)(6)(9)(10)(26)43040人阅读
Spring(6)
项目使用的Spring版本比较旧是3.0.6版本,由于需要进行定时任务,就决定使用Spring自带的scheduled task。
在网上找了很多文章,也查看了Spring3.0.6的官方文档,按照网上和文档所说,可以使用注解或者配置两种方法之一都行,但是我发现单独使用两种方法都不行,怎么配置任务都无法运行。
最后看到一篇文章说两种方法同时用,才成功执行定时任务,可能是个Bug,我试了下,同时使用注解和XML配置后,任务确实成功执行了。
XML配置中,只需要配置一个方法即可,其他方法也能跟着运行了,而且XML中配置的定时时间会被注解覆盖掉,只能先这么做了,期待高手解答原因。
难道真的是Spring3.0.6的Bug??
Spring配置如下:
&?xml version=&1.0& encoding=&UTF-8&?&
&beans xmlns=&http://www.springframework.org/schema/beans& xmlns:xsi=&http://www.w3.org/2001/XMLSchema-instance&
xmlns:jee=&http://www.springframework.org/schema/jee&
xmlns:tx=&http://www.springframework.org/schema/tx&
xmlns:context=&http://www.springframework.org/schema/context&
xmlns:aop=&http://www.springframework.org/schema/aop&
xmlns:task=&http://www.springframework.org/schema/task&
xsi:schemaLocation=&http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd&
default-lazy-init=&true& default-autowire=&byName&&
&!-- 配置注解扫描 --&
&context:annotation-config /&
&!-- 自动扫描的包名 --&
&context:component-scan base-package=&com.demo& /&
&!-- Spring定时器注解开关--&
&task:annotation-driven /&
&!-- 此处对于定时时间的配置会被注解中的时间配置覆盖,因此,以注解配置为准 --&
&task:scheduled-tasks scheduler=&myScheduler&&
&task:scheduled ref=&scheduledTaskManager& method=&autoCardCalculate& cron=&1/5 * * * * *&/&
&/task:scheduled-tasks&
&task:scheduler id=&myScheduler& pool-size=&10&/&
&aop:aspectj-autoproxy /&
&!-- 加载配置文件 --&
&bean id=&propertyConfigurer& class=&org.springframework.beans.factory.config.PropertyPlaceholderConfigurer&&
&property name=&locations&&
&value&classpath:config.properties&/value&
&/property&
执行任务的POJO类如下:
package com.demo.
import org.apache.log4j.L
import org.springframework.beans.factory.annotation.A
import org.springframework.scheduling.annotation.S
import org.
import java.util.D
* Created with IntelliJ IDEA.
* Function: Spring定时任务管理
@Component(&scheduledTaskManager&)
public class ScheduledTaskManager {
* cron表达式:* * * * * *(共6位,使用空格隔开,具体如下)
* cron表达式:*(秒0-59) *(分钟0-59) *(小时0-23) *(日期1-31) *(月份1-12或是JAN-DEC) *(星期1-7或是SUN-SAT)
* 定时卡点计算。每天凌晨 02:00 执行一次
@Scheduled(cron = &0 0 2 * * *&)
public void autoCardCalculate() {
System.out.println(&定时卡点计算... & + new Date());
对于这个问题,期待高手解答,也希望大家能一起讨论下。
替换成Sping3.2.2之后,就可以直接在XML中配置,而不需要在方法上使用注解配置时间了。
感谢4楼,5楼解答:
问题在于Spring全局配置:default-lazy-init=&true&
加上这一句启动的时候还怎么初始化,如果不想改这个配置,那在bean上加个注解
@Component(&scheduledTaskManager&)&
@Lazy(value=&false&)
public class ScheduledTaskManager {&
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1256662次
积分:8991
积分:8991
排名:第1287名
原创:70篇
转载:66篇
评论:207条
(7)(2)(1)(1)(1)(1)(2)(1)(1)(1)(6)(3)(1)(3)(3)(2)(5)(2)(1)(5)(4)(2)(3)(3)(1)(2)(6)(13)(20)(14)(14)(9)(译).NET4.X并行任务Task需要释放吗?
我多次获得这样一个问题:
&&&&&&&& &Task实现了IDisposable接口并且公开Dispose()方法,这是否意味着我们要对所有的任务进行释放吗?&
1.&&&&&&&& 这是我对该问题的简要回答:
&不是,不用释放你持有的Task。&
2.&&&&&&&& 这是我对该问题的中篇回答:
&不是,不用释放你持有的Task,除非性能报告或可伸缩性测试报告显示你需要释放Task以满足你的性能目标。如果你发现一个需要被释放的Task,必须100%确保在你的释放点处该Task已经完成并且没有被其他地方在使用。&
3.&&&&&&&& 下面,你可以找一个休闲的阅读时间,这是我对该问题的长回答:
为什么要调用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就是一个好选择。
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模式(&分支/合并&模式)中那么它就很容易知道什么时候完成它们和什么时候没有人再使用它们,比如:
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的延续任务时,就很难判断它什么时候完成它们和什么时候没有人再使用它们,比如:
Compute1Async().ContinueWith(t1 =&&
&&&&t1.Dispose();&
示例成功的释放掉Compute1Async()返回的Task,但是它忽略了如何释放ContinueWith()返回的Task。当然,我们能使用同样的方法释放这个Task。
Compute1Async().ContinueWith(t1 =&&
&&&&t1.Dispose();&
}).ContinueWith(t2 =& t2.Dispose());
但是我们不能释放第二个ContinueWith()返回的Task。即使使用C#5.0中新的async/await异步方法也不能解决。例如:
string s1 = await Compute1Async();&
string s2 = await Compute2Async(s1);&
string s3 = await Compute3Async(s2);
如果想释放这些Task,我需要进行像下面这样的重写:
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()方法。
本站推荐文章:
使用.NET开发程序,因为元数据存在于程序集中,可以轻易的被反编译成源代码。在分发给...
.NET FrameWork 2.0 并没有提供JSON 字符串对象化工具,因此尝试写了这个转换器, 目前...
1, 功能描述 仿QQ短信(QQ邮箱里面的功能),登录,短息主界面,发信息,单个话题对话。...
在我们开发一个ASP.NET网站的过程中,其实有很多地方都是可以使用缓存的,只是由于ASP...
没办法,有时候程序员做事需要非程序员去提醒,去找解决办法,我只能这样了 ASP.Net 1.1...
先看整体项目布局(如下图所示),有个大体的了解。Jasen.SilverlightService为silver...
我们在编写 .NET 程序时,经常会在该程序的关于本软件对话框中给出这个程序的编译时间...
本文旨在帮助那些为网站发送手机短信正在寻求解决方案还未最终找到解决方案的朋友提供...
在程序设计中,涉及数据存储和数据交换的时候,不管是B/S还是C/S模式 ,都有这样一个...
本文PDF下载 转载请注明出处 文章概述 在三层开发中,业务逻辑层不仅会在本系统中使用...
本站热点文章:
最近项目中用到window服务程序,以前没接触过,比较陌生,花了两天的时间学习了下,写...
使用.NET开发程序,因为元数据存在于程序集中,可以轻易的被反编译成源代码。在分发给...
提供流程设计,调试,图形化状态跟踪,自动生成数据页面,格式转换,等功能 原计划准备在春...
在程序设计中,涉及数据存储和数据交换的时候,不管是B/S还是C/S模式 ,都有这样一个...
熟悉.NET的开发者们应该都知道里面有一个GC.Collect()吧,它的功能就是强制对所有代进...
.NET FrameWork 2.0 并没有提供JSON 字符串对象化工具,因此尝试写了这个转换器, 目前...
/// summary /// 动态调用WebService的代理类 /// /summary class WebServiceHelper {...
1.ASP时代的HTTP请求处理过程 在IIS的应用程序映射中,IIS会将对asp和asa文件的请求转...
using S using System.D using System.DirectoryS using System.Co...
对于广大的Web开发人员,维护Web访问日志是一件经常性的工作,随着时间和访问量的提升,W...
------分隔线----------------------------自由、创新、研究、探索
Linux/Windows Mono/DotNet [ Open Source .NET Development/ 使用开源工具进行DotNet软件开发]锐意进取,志存高远.成就梦想,只争朝夕.从你开始,创新世界.【That I exist is a perpetual supprise which is life. Focus on eCommerce】
& & &&提到例子都是数据并行,但这并不是并行化的唯一形式,在.Net4之前,必须要创建多个线程或者线程池来利用多核技术。现在只需要使用新的Task实例就可以通过更简单的代码解决命令式任务并行问题。
1.Task及它的生命周期
& & &&一个Task表示一个异步操作,它的创建和执行都是独立的,因此可以对相关操作的执行拥有完全的控制权;当有很多异步操作作为Task实例加载的时候,为了充分利用运行时的逻辑内核,任务调度器会尝试并行的运行这些任务,当然任务都是有额外的开销,虽然要小于添加线程的开销;
& & & 对Task实例的生命周期的理解非常重要。一个Task的执行,取决于底层硬件和运行时可用的资源。因此Task实例的状态会不断的发生改变,而一个Task实例只会完成其生命周期一次,当Task到达它三种可能的最终状态只后,它就回不去之前的任何状态了。
& & & Task实例有三种可能的初始状态,Created是Task构造函数创建实例的初始状态,WaitForActivation是子任务依赖其他任务完成后等待调度的初始状态,WaitingToRun是通过TaskFactory.StartNew所创建任务的初始状态。表示正在等待调度器挑选自己并运行。
& & & 任务开始执行,状态就变为TaskStatus.Runing。如果还有子任务,主任务的状态会转变到TaskStatus.WaitingForChildrenToComplete状态。并最终到达,Canceled,Faulted和RunToCompletion 三种状态。从字面理解就是任务取消,出错和完成。
2.任务并行。
& & &前面我们通过Parallel.Invoke来并行加载方法。
Parallel.Invoke(GenerateAESKeys,GenerateMD5Has);
& & &通过Task实例也能完成同样的工作。
var t1 = new Task(GenerateAESKeys);
var t2 = new Task(GenerateMD5Has);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
&Start方法对委托进行初始化。&WaitAll方法会等待两个任务的执行完成之后再往下走。
可以看见,执行过程中,任务的状态不断的发生变化。可以给WaitFor方法加上毫秒数。看任务是否会在指定时间内完成。
if(!Task.WaitAll(new[]{t1,t2},3000))
Console.WriteLine("任务执行超过3秒");
Console.WriteLine(t1.Status.ToString());
Console.WriteLine(t2.Status.ToString());
即使到达了指定时间,任务还是继续执行。
同样任务本身也是可以等待
if (t1.Wait(3000))
Console.WriteLine("任务t1执行超过3秒");
Console.WriteLine(t1.Status.ToString());
3.通过取消标记取消任务。
& & 可以通过CancellationToken 来中断任务的执行。这需要再委托中添加一些代码,创建可以取消的任务。
private static void GenerateMD5HasCancel(CancellationToken ct)
ct.ThrowIfCancellationRequested();
var sw = Stopwatch.StartNew();
for (int i = 0; i & NUM_AES_KEYS; i++)
var md5M = MD5.Create();
byte[] data = Encoding.Unicode.GetBytes(Environment.UserName + i);
byte[] result = puteHash(data);
string hexString = ConverToHexString(result);
ct.ThrowIfCancellationRequested();
Console.WriteLine("MD5:" + sw.Elapsed.ToString());
Console.WriteLine("任务开始...");
var cts = new CancellationTokenSource();
var ct = cts.T
var sw = Stopwatch.StartNew();
var t1 = Task.Factory.StartNew(() =& GenerateMD5HasCancel(ct), ct);
var t2 = Task.Factory.StartNew(() =& GenerateAESKeysCancel(ct), ct);
//1秒后取消任务
Thread.Sleep(1000);
cts.Cancel();
if (!Task.WaitAll(new[] { t1,t2}, 1000))
Console.WriteLine("任务执行超过1秒");
Console.WriteLine(t1.Status.ToString());
catch (AggregateException ex)
foreach (var exc in ex.InnerExceptions)
Console.WriteLine(exc.ToString());
if (t1.IsCanceled)
Console.WriteLine("任务1取消了...");
Console.WriteLine(sw.Elapsed.ToString());
Console.WriteLine("结束");
CancellationTokenSource能够初始化取消的请求,而CancellationToken能将这些请求传递给异步操作;上面的方法通过Task类的Factory方法得到一个TaskFactory实例,相比Task直接创建任务,这个实例可以使用更多的功能。而StartNew 等价于用Task构造函数创建一个Task并调用Start方法执行。
直接在Debug下面运行,程序会在异常的地方中断。直接运行exe得到上面的结果。&
ThrowIfCancellationRequested在每一次循环迭代都会执行,内部是判断任务取消后抛出一个OperationCanceledException的异常,来避免运行不必要的循环和其他命令。
public void ThrowIfCancellationRequested()
if (IsCancellationRequested)
ThrowOperationCanceledException();
private void ThrowOperationCanceledException()
throw new OperationCanceledException(Environment.GetResourceString("OperationCanceled"), this);
如果有代码正在等待取消,还会自动抛出一个TaskCanceledException异常。会包含在AggregateException中。
4.处理异常。
& 修改上面的方法抛出一个异常。
private static void GenerateMD5HasCancel(CancellationToken ct)
ct.ThrowIfCancellationRequested();
//....if (sw.Elapsed.TotalSeconds & 0.5)
throw new TimeoutException("超时异常0.5秒");
ct.ThrowIfCancellationRequested();
Console.WriteLine("MD5:" + sw.Elapsed.ToString());
修改Main方法的Catch。
if (t1.IsFaulted)
foreach (var exc in ex.InnerExceptions)
Console.WriteLine(exc.ToString());
Console.WriteLine(t1.Status.ToString());
执行结果:
当出现异常时,任务的状态就会转换为Faulted。并不会影响另外一个任务的执行。
5.从任务返回值。
前面的方法都是没有返回值,得到任务的返回值需要使用Task&TResult&实例,TResult要替换为返回的类型。修改AES方法。返回一个指定前缀的List&String&
GenerateMD5HasList:
&View Code
Console.WriteLine("任务开始...");
var cts = new CancellationTokenSource();
var ct = cts.T
var t1 = Task.Factory.StartNew(() =& GenerateMD5HasList(ct,'A'), ct);
//等待执行完成
t1.Wait();
var res = t1.R
for (int i = 0; i & res.C i++)
Console.WriteLine(res[i]);
而这时的StartNew创建的类型是Task&List&String&&.StartNew源码如下:
public Task&TResult& StartNew&TResult&(Func&TResult& function)
StackCrawlMark stackMark = StackCrawlMark.LookForMyC
Task currTask = Task.InternalC
return Task&TResult&.StartNew(currTask, function, m_defaultCancellationToken,
m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark);
我们还可以将任务串联起来。比如上面的代码。避免写太多代码来检查前面一个任务是否完成。而ContinueWith这个方法可以用来串联多个任务。
var t1 = Task.Factory.StartNew(() =& GenerateMD5HasList(ct,'A'), ct);
var t2 = t1.ContinueWith((t) =&
for (int i = 0; i & t.Result.C i++)
Console.WriteLine(t.Result[i]);
//可以等待t2执行完成
t2.Wait();
如果需要设置继续的条件,就要用到,它是一个枚举类型,用来控制另一个任务执行和调度的可选行为
var t2 = t1.ContinueWith((t) =& OtherMethod(t), TaskContinuationOptions.NotOnCanceled);
&NotOnCanceled,就是表示上个任务不取消的情况下执行。例如还有NotOnFaulted.如果上一个任务抛出了异常,那么就不会执行。这里就不一一例举了。
&小结:这一章主要是将了基于任务的编程模型,学习了任务的创建、状态,以及如何取消、捕获异常和获得返回值,并能串行任务,任务的延续不仅能简化代码,而且还能帮助调度器对很快就要执行的任务采取正确的操作。下一章学习并发集合。
阅读书籍:《》&链接: 下载链:&&&密码: fn2d
阅读(...) 评论()
随笔 - 14461
评论 - 973

我要回帖

更多关于 jenkins 多任务并行 的文章

 

随机推荐