在上篇文章中我们看过了如何创建Task,本篇文章就各种类型Task的使用进行说明。
首先我们来看看延续的Task,所谓的延续的Task就是在第一个Task完成后自动启动下一个Task。我们通过ContinueWith方法来创建延续的Task。我们假设有一个接受xml解析的服务,首先从某个地方接受文件,然后解析入库,最后返回回执是否解析正确:
1
2
3
4
5
6
7
8
9
|
[TestMethod]
public
void
TaskParallelPrint()
{
var ReceiveTask =
new
Task(() => ReceiveXml());
var ResolveTask = ReceiveTask.ContinueWith<
bool
>((r) => ResolveXml());
var SendFeedBackTask = ResolveTask.ContinueWith<
string
>((s) => SendFeedBack(s.Result));
ReceiveTask.Start();
Console.WriteLine(SendFeedBackTask.Result);
}
|
在每次调用ContinueWith方法时,每次会把上次Task的引用传入进来,以便检测上次Task的状态,比如我们可以使用上次Task的Result属性来获取返回值。上面的代买我们也可以这么写:
1
2
3
4
5
6
7
8
|
[TestMethod]
public
void
TaskParallelPrint()
{
var SendFeedBackTask = Task.Factory.StartNew(() => ReceiveXml())
.ContinueWith<
bool
>(s => ResolveXml())
.ContinueWith<
string
>(r => SendFeedBack(r.Result));
Console.WriteLine(SendFeedBackTask.Result);
}
|
有些情况下我们需要创建嵌套的Task,嵌套里面又分为分离的和不分离的。其创建的方式很简单,就是在Task的body里面创建一个新的Task。如果新的Task未指定AttachedToParent选项,那么就是分离嵌套的。我们看下面这段代码:
1
2
3
4
5
6
7
8
9
10
11
12
|
var outTask = Task.Factory.StartNew(() =>
{
Console.WriteLine(
"Outer task beginning..."
);
var childTask = Task.Factory.StartNew(() =>
{
Thread.SpinWait(3000000);
Console.WriteLine(
"Detached nested task completed."
);
});
});
outTask.Wait();
Console.WriteLine(
"Outer task completed."
);
Console.ReadKey();
|
我们可以看到运行结果是:
上面的代码中outTask.Wait()表示等待outTask执行完成。
我们将上面的代码加上TaskCreationOptions选项:
1
2
3
4
5
6
7
8
9
10
11
12
|
var outTask = Task.Factory.StartNew(() =>
{
Console.WriteLine(
"Outer task beginning..."
);
var childTask = Task.Factory.StartNew(() =>
{
Thread.SpinWait(3000000);
Console.WriteLine(
"Detached nested task completed."
);
},TaskCreationOptions.AttachedToParent);
});
outTask.Wait();
Console.WriteLine(
"Outer task completed."
);
Console.ReadKey();
|
看到运行结果:
如何取消一个Task呢,我们通过cancellation的tokens来取消一个Task。在很多Task的Body里面包含循环,我们可以在轮询的时候判断IsCancellationRequested属性是否为True,如果是True的话,就可以停止循环以及释放资源,同时抛出OperationCanceledException异常出来。来看一段示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
var tokenSource =
new
CancellationTokenSource();
var token = tokenSource.Token;
var task = Task.Factory.StartNew(() =>
{
for
(var i = 0; i < 10000000; i++)
{
if
(token.IsCancellationRequested)
{
Console.WriteLine(
"Task cacel started..."
);
throw
new
OperationCanceledException(token);
}
}
},token);
token.Register(() =>
{
Console.WriteLine(
"Canceled"
);
});
Console.WriteLine(
"Press enter again to cancel task"
);
Console.ReadKey();
tokenSource.Cancel();
try
{
task.Wait();
}
catch
(AggregateException e)
{
foreach
(var v
in
e.InnerExceptions)
Console.WriteLine(
"msg: "
+ v.Message);
}
Console.ReadKey();
|
本篇文章中我们看过了创建各种不同的Task以及如何取消Task,下篇文章中会就异常处理以及Task Laizy进行说明