一、概述
本质上,Task和ThreadPool使用的是同一个线程池,一般来说,Task效率更高点。
Task也是Parallel类和PLINQ的基础。
二、创建Task
先创建,后启动:
var task = new Task (() => Console.Write ("Hello"));
// ...
task.Start();
创建与启动:
Task.Factory.StartNew (() => Console.WriteLine ("Hello from a task!"));
Task的子类Task<TResult>提供了在任务结束时接收返回值的方法:
Task<string> task = Task.Factory.StartNew<string> (() => // 开始任务
{
using (var wc = new System.Net.WebClient())
return wc.DownloadString ("http://www.linqpad.net");
});
RunSomeOtherMethod(); // 我们可以并行的做其它工作...
string result = task.Result; // 等待任务结束并获取结果
注:使用 RunSynchronuosly 代替 Start 可实现同步开启任务。
三、等待Task
两种方式可以等待Task:
- 调用Wait(),WaitAny(),WaitAll()
- 访问 Result 属性(仅当Task<TResult>类型时)
四、异常处理
一般无需在Task中处理异常,当调用方等待Task时,Task中未处理的异常都会封装成一个AggregateException对象抛出来给调用方。
int x = 0;
Task<int> calc = Task.Factory.StartNew (() => 7 / x);
try
{
Console.WriteLine (calc.Result);
}
catch (AggregateException aex)
{
Console.Write (aex.InnerException.Message); // 试图以 0 为除数
}
注:在.NET 4.5以后,Task中未处理的异常会被忽略。
五、取消Task
启动Task时传入一个取消标记,即可通过取消标记取消Task。
var cancelSource = new CancellationTokenSource();
CancellationToken token = cancelSource.Token;
Task task = Task.Factory.StartNew (() =>
{
// 做些事情...
token.ThrowIfCancellationRequested(); // 检查取消请求
// 做些事情...
}, token);
// ...
cancelSource.Cancel();
调用方可抓取Task取消异常:
try
{
task.Wait();
}
catch (AggregateException ex)
{
if (ex.InnerException is OperationCanceledException)
Console.Write ("Task canceled!");
}
五、Task延续
有时,我们需要在一个Task完成或失败时马上启动另一个Task,则可以用ContinueWith实现。
Task task1 = Task.Factory.StartNew (() => Console.Write ("antecedant.."));
Task task2 = task1.ContinueWith (ant => Console.Write ("..continuation"));
Task.Factory.StartNew<int> (() => 8)
.ContinueWith (ant => ant.Result * 2)
.ContinueWith (ant => Math.Sqrt (ant.Result))
.ContinueWith (ant => Console.WriteLine (ant.Result)); // 4
结构图:
参考链接: