.Net4.0 任务(Task)

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

作用
Task 管理工作单元
Task<TResult> 管理带返回值的工作单元
TaskFactory 创建任务
TaskFactory<TResult> 创建任务或者有相同返回值的延续任务
TaskScheduler 管理任务调度
TaskCompletionSource 手动控制任务工作流

任务用来并行地执行工作,充分地利用多核:事实上,Parallel和PLINQ内部就是建立在任务并行的结构上。

任务提供了一系列强大的特性来管理工作单元,包括:

  • 协调任务调度
  • 建立一个任务从另一个任务中启动的父子关系
  • 实现合作取消(cooperative cancellation)模式
  • 无信号的任务等待
  • 附加延续任务(continuation)
  • 基于多个祖先任务调度一个延续任务
  • 传递异常到父任务、延续任务或任务消费者

同时任务实现了一个本地工作队列,它允许你高效地创建快速执行的子任务而不用遭受在单个工作队列时的竞争花费。任务并行库让你用最小的花费来创建成百上千的任务,但是如果你想创建上百万个任务,就必须分割这些任务到更大的工作单元,以保持效率。

创建与启动任务

有两种方法可以创建任务,一种是通过TaskFactory的StartNew()方法创建并启动任务;另一种是调用Task构造函数创建,然后手动启动任务。需要注意的是,任务启动后并不会立即执行,它是由任务调度器(TaskScheduler)来管理的。

  • TaskFactory的StartNew()方法创建任务的示例如下:
    //没有返回值
    Task.Factory.StartNew(() => Console.WriteLine("Task Created!"));
    //有返回值
    var task = Task.Factory.StartNew<string>(() => "Task Created!");
    Console.WriteLine(task.Result);
  • 调用Start方法手动启动的示例如下:
    var task = new Task<string>(() => "Task Created!");
    task.Start();//异步执行
    Console.WriteLine(task.Result);
  • 调用RunSynchronously方法手动启动的示例如下:
    var task = new Task<string>(() => "Task Created!");
    task.RunSynchronously();//同步执行
    Console.WriteLine(task.Result);

也可以在创建任务时指定一个任务状态参数,可以通过任务的AsyncState属性来访问该参数。示例:

var task = Task.Factory.StartNew(state => "hello " + state, "Mike");
Console.WriteLine(task.AsyncState);
Console.WriteLine(task.Result);

你还可以指定一个任务创建选项(TaskCreationOptions) ,这个枚举类型有以下枚举值:None,LongRunning,PreferFairness,AttachedToParent。下面解释各个枚举值的作用。

  • LongRunning:顾名思义就是长时间运行的任务,此选项建议任务调度器分配一个专用的线程给任务。这样做的原因是:长时间运行的任务可能会阻塞任务队列,导致那些短小的任务一直得不到执行。LongRunning也适合那些阻塞的任务。
  • PreferFairness:公平第一,此选项建议任务调度器尽量按照任务的启动时间来调度任务。但是它通常可能不这样做,因为它使用本地工作偷取队列(local work-stealing queues)优化任务调度。这个优化对那些非常小的任务很有用。
  • AttachToParent:附加到父任务,此选项用来创建子任务。创建子任务示例:

    第一种方式:
    var parent = Task.Factory.StartNew(() =>
    {
        var nonChildTask = Task.Factory.StartNew(
            () => Console.WriteLine("I'm not a child task.")
        );
        var childTask = Task.Factory.StartNew(
            () => Console.WriteLine("I'm a child task."),
        TaskCreationOptions.AttachedToParent);
    });
    第二种方式:
    Task parent=new Task(()=>
    {
        DoStep1();
    });
    Task task2 = parent.ContinueWith ((PrevTask) =>
    {
        DoStep2();
    });
    parent.Start();

任务等待

任务可以通过Wait()成员方法或Result属性来等待任务完成。

当调用Result属性时,将会执行下列操作:

  1. 如果任务已结束,返回任务结果
  2. 如果任务已开始,等待任务结束
  3. 如果任务尚未开始执行,则在当前线程执行任务

Task.WaitAny()静态方法等待任何一个任务完成。示例:

var tasks = new Task[3];
for (int i = 0; i < tasks.Length; i++)
{
    int taskIndex = i;
    tasks[i] = Task.Factory.StartNew(() =>
    {
        int seed=Guid.NewGuid().GetHashCode();
        int waitTime = new Random(seed).Next(10, 100);
        Thread.Sleep(waitTime);
        Console.WriteLine("Task{0} Finished", taskIndex);
    });
}
Task.WaitAny(tasks);
Console.WriteLine("已有任务完成");

Task.WaitAll()静态方法等待所有任务完成。即使有任务抛出异常也不会终止等待,它会在所有任务完成之后抛出一个AggregateException异常,这个异常聚合了所有任务抛出的异常。示例:

var tasks = new Task[3];
for (int i = 0; i < tasks.Length; i++)
{
    int taskIndex = i;
    tasks[i] = Task.Factory.StartNew(() =>
    {
         int waitTime = new Random(Guid.NewGuid().GetHashCode()).Next(10, 100);
         Thread.Sleep(waitTime);
         Console.WriteLine("Task{0} Finished", taskIndex);
    });
}
Task.WaitAll(tasks);
Console.WriteLine("所有任务完成");

异常处理

默认情况下任务未处理的异常会终止应用程序。需要指出的是任务中未处理的异常不会立即导致应用程序终止,异常要延迟到垃圾回收器回收任务并调用Finalize方法时才会终止程序。如果读取了任务的Exception属性,这个操作将阻止随后的应用程序终止。
当等待任务完成时,所有未处理的异常会传递到调用方。
Wait()方法超时的异常也必须处理,否则导致应用程序终止。
子任务中未处理的异常会冒泡传递到父任务;嵌套任务中的非子任务的异常不会传递到这个任务的上一层任务,需要单独处理,否则将导致应用程序终止。

var task = Task.Factory.StartNew(() =>
{
    Task.Factory.StartNew(() => { throw null; }, TaskCreationOptions.AttachedToParent);
    Task.Factory.StartNew(() => { throw null; }, TaskCreationOptions.AttachedToParent);
    Task.Factory.StartNew(() => { throw null; }, TaskCreationOptions.AttachedToParent);
});
task.Wait();

TaskScheduler.UnobservedTaskException静态事件提供了最后一种手段处理所有未处理异常。通过处理这个事件,就不用终止应用程序,而用你自己的异常处理逻辑替代它。

取消任务

当创建任务时,可以传入一个取消令牌(CancelationToken)参数,这样就可以安全的取消任务。示例:

var source = new CancellationTokenSource();
var token = source.Token;
var task = Task.Factory.StartNew(() =>
{
    Console.WriteLine("Task starting...");
    while (true)
    {
        token.ThrowIfCancellationRequested();
        Console.WriteLine("I'm alive. {0}",DateTime.Now);
        Thread.Sleep(1000);
    }
},token);

Task.Factory.StartNew(() =>
{
    Thread.Sleep(4500);
    source.Cancel();
});

try
{
    task.Wait();
    Console.WriteLine("Task stopped.");
}
catch (AggregateException e)
{
    if (e.InnerException is OperationCanceledException)
    {
        Console.WriteLine("Task canceled.");
    }
    else
    {
        Console.WriteLine("errors.");
    }
}

通过调用CancellationTokenSource的Cancel()方法取消任务,这个并不会立即终止任务,一直延迟到任务下次检测是否取消时才通过抛出OperationCanceledException终止任务。

如果想通过直接抛出OperationCanceledException异常的方式取消任务,则需要在任务中传入CancelationToken参数,否则就不能将任务的状态为TaskStatus.Canceled并触发OnlyOnCanceled延续任务。

此外,取消令牌也可以传递到Wait和CancelAndWait方法中来取消等待。

时间: 2024-08-03 02:16:13

.Net4.0 任务(Task)的相关文章

NET4.0 使用Task,报出异常,程序中断退出

问题描述 先贴一个异常信息代码比较多,不贴了,思路是这样的,我的任务个数比较多,所以使用for循环ContinueWith下一个任务.任务A.Start();循环任务{任务Temp=任务A.ContinueWith<O>(方法);}执行的任务是通过webservice加载外网服务器数据写到本地,每个一段时间就要执行一次.在本机测试可以通过,稳定运行很久都没有挂掉,但是挂到服务器上之后,就经常会挂掉报出上面的错误第一次用这个Task,不知道使用的对不对,希望各位帮忙一下,不胜感激!分比较少,抱歉

.NET4.0新功能:任务(Task)

用过.NET线程池的程序员都知道通过调用ThreadPool类的QueueUserWorkItem 方法把要执行的代码放入线程池去执行.由于.NET FCL的强大,使得这个操作极 其简便.但使用线程池有个明显的不足之处,那就是我们无法获取线程池执行方 法的返回值,因为WaitCallback委托的返回值为void.注:WaitCallback委托的 原型为:public delegate void WaitCallback(Object state). 比如,我们有个方法代码是这样的: publ

《圣殿祭司的ASP.NET4.0专家技术手册》----1-1 ASP.NET平台的三分天下

1-1 ASP.NET平台的三分天下 圣殿祭司的ASP.NET4.0专家技术手册 如果访问微软www.asp.net网站,会发现ASP.NET技术目前有3位成员:Web Form.MVC和Web Pages,如图1-1所示.它们各有不同的定位与特色,彼此的开发方式也不相同.目前,使用人数与市场占有率最高的仍是Web Form,而MVC近两年有不少技术玩家和项目采用,至于Web Pages,则是另外的Web Matrix开发工具预定的网页开发技术,它走更易于使用的开发路线. 你心里可能有疑问:"为

vs201-mvc 提交html代码,问题(VS2013、win7、net4.0)不用XSS验证

问题描述 mvc 提交html代码,问题(VS2013.win7.net4.0)不用XSS验证 本来这应该不是问题!!但是可能是我的环境有点复杂吧! 我现在用的是32位win7系统,VS2013.建立mvc只能创建mvc4,但是由于我租用的web空间现在只支持framework 4.0!!,只好在:项目→属性→选择.NET framework 4 !! 现在我在web.config中设置了 又在Controller的方法中 添加了[ValidateInput(false)]标签,可还是不行!!最

.NET4.0线程池的Cooperative Cancellation模式

刚装了VS2010RC版,体验一下.NET4.0线程池新增的Cooperative Cancellation模式. 用过.NET线程池的人都知道,一旦把要执行的代码交给线程池去执行后,我们 基本上就失去了代码在运行中的控制能力.比如,我们想在某个时刻取消这段代 码的执行,就得另想一个办法.随着.NET4.0到来,这个问题得到了解 决..NET4.0引入了一种新的设计模式---合作取消模式(Cooperative Cancellation). .NET4.0的System.Threading命名空

Win7 .net4.0安装未成功如何解决

  知识点分析: win7 .net4.0安装未成功. 操作步骤: 主要原因是Windows update的临时文件损坏,建议重命名该文件夹. 1. 开始--运行--cmd--键入net stop WuAuServ回车(停止windows update服务); 2. 开始--运行--键入%windir%回车(打开系统目录); 3. 将SoftwareDistribution文件夹重命名为SDold; 4. 开始--运行--cmd--键入net start WuAuServ回车; 5. 可以正常安

安装.net4.0报错

知识点分析: 安装.net4.0提示hresult 0xc8000247 操作步骤: 先安装英特尔快速存储技术,重启后再安装.net4.0,测试正常安装.

《圣殿祭司的ASP.NET4.0专家技术手册》---- 1-6 VS 2010 SP1安装与三个扩展管理工具

1-6 VS 2010 SP1安装与三个扩展管理工具 圣殿祭司的ASP.NET4.0专家技术手册 2011年3月,微软推出VS 2010 SP1软件补丁,里面包含许多新功能与问题修正,其中与Web开发相关新功能有: IIS 7.5 Express精简版网页服务器的支持(IIS 7.5 Express需额外下载安装): SQL Server CE 4.0的支持(SQL Server CE 4.0需额外下载安装): Razor语法支持: 可部署的依赖性支持(Deployable dependenci

vs2010安装到.net4.0 安装出错

问题描述 系统是win732位错误信息:02/25/11,18:58:28]Microsoft.NETFramework4:[2]Errorcode-939523550forthiscomponentisnotrecognized.[02/25/11,18:58:28]Microsoft.NETFramework4:[2]ComponentMicrosoft.NETFramework4returnedanunexpectedvalue.试过单独去下载.net4.0安装程序,也是安装错误提示err