I. 概述
在.NET Framework 4之前,如果我们要使用多核或者多CPU的优势,我们需要使用多线程的方式(大家感兴趣可以参考我的另一篇关于线程方面的文章)。在.NET Framework 4中,微软提供了一个新的命名空间System.Threading.Tasks来实现并行,通常被称为TPL。TPL引入了一种新的基于task的编程模型,我们使用它可以很轻松的实现并行,使开发人员从跟底层的Thread打交道的方式解放出来。但是注意task并没有取代thread, 而实际上task是基于thread的,这一系列文章之后我会写一篇关于二者之间关系的文章。
II. 创建和启动Task
1: static void Main(string[] args)
2: {
3:
4: //Action
5: Task task1 = new Task(new Action(CubicSum));
6: //Anonymous Method
7: Task task2 = new Task(delegate { CubicSum(); });
8: //Lambda Expression and a named method
9: Task task3 = new Task(() => CubicSum());
10: //Lambda Expression and an anonymous method
11: Task task4 = new Task(() => { CubicSum(); });
12:
13: task1.Start();
14: task2.Start();
15: task3.Start();
16: task4.Start();
17:
18: Console.ReadLine();
19: }
在上述代码中,我们使用了多种方式,大家可以自己尝试一下。是不是创建和启动一个task很容易。注意,要引入System.Threading.Tasks。
在创建Task的时候,我们还可以通过TaskCreationOptions枚举为它设置一些选项。
None | Task将采用默认行为 |
AttachedToParent | Task将依附于它的父Task |
LongRunning | Task将长时间运行 |
PreferFairness | 请求Task Schedule使这个task尽量“公平”地运行 |
III. 获得Task执行后的返回结果
可以使用Task<TResult>来获得Task执行后的返回结果。我们改写QuadraticSum()方法,让它可以返回值。
1: private static double QuadraticSum()
2: {
3: double sum = 0;
4: var sw = Stopwatch.StartNew();
5: for (int i = 0; i < NUM_MAX; i++)
6: {
7: sum = sum + (2 * i + 1) * (i + 1) * i / 6;
8: }
9:
10: return sum;
11: }
12:
13:
14: static void Main(string[] args)
15: {
16:
17: Task<double> task1 = new Task<double>(() => QuadraticSum());
18:
19: task1.Start();
20:
21: Console.WriteLine("Result is: {0}",task1.Result);
22:
23: Console.ReadLine();
24: }
IV. 取消Task
1: private const int NUM_MAX = 100000000;
2:
3: static void Main(string[] args)
4: {
5: //create a CancellationTokenSource
6: CancellationTokenSource tokenSource = new CancellationTokenSource();
7:
8: //create a CancellationToken via CancellationTokenSource
9: CancellationToken token = tokenSource.Token;
10:
11: //create a Task with a CancellationToken
12: Task task1 = new Task(() =>
13: {
14: double sum = 0;
15: for (int i = 0; i < NUM_MAX; i++)
16: {
17: sum = sum + (2 * i + 1) * (i + 1) * i / 6;
18: }
19: },token);
20:
21: task1.Start();
22:
23: Console.WriteLine("Cancelling task");
24: //cancel the task
25: tokenSource.Cancel();
26:
27: Console.ReadLine();
28: }
1. 通过上述代码我们可以看到如何Cancel一个Task的基本步骤:
第一步:创建一个CancellationTokenSource
第二步:创建一个CancellationToken
第三步:把CancellationToken作为一个参数,传递到Task中
第四步:调用CancellationTokenSource的Cancel()方法
当然我们也可以取消多个Task:只要把CancellationToken作为一个参数,传递到每一个Task中,然后当系统调用CancellationTokenSource的Cancel()方法时,就可以取消所有使用CancellationToken的Task, 当然这些Task要使用同一个CancellationToken
2. 使用连接CancellationToken类取消Task
我们可以使用System.Threading.CancellationTokenSource.CreateLinkedTokenSource()来连接多个CancellationTokenSource,只要其中一个调用CancellationTokenSource的Cancel()方法,所有使用这个连接CancellationTokenSource的Task都会被取消。
1: private const int NUM_MAX = 100000000;
2:
3: static void Main(string[] args)
4: {
5:
6: //create multipule CancellationTokenSources
7: CancellationTokenSource tokenSource1 = new CancellationTokenSource();
8: CancellationTokenSource tokenSource2 = new CancellationTokenSource();
9: CancellationTokenSource tokenSource3 = new CancellationTokenSource();
10:
11: //linked these multipule CancellationTokenSources
12: CancellationTokenSource LinkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(tokenSource1.Token, tokenSource2.Token, tokenSource3.Token);
13:
14: //create a CancellationToken via linked CancellationTokenSource
15: CancellationToken token = LinkedTokenSource.Token;
16:
17: //create a Task with a CancellationToken
18: Task task1 = new Task(() =>
19: {
20: double sum = 0;
21: for (int i = 0; i < NUM_MAX; i++)
22: {
23: sum = sum + (2 * i + 1) * (i + 1) * i / 6;
24: }
25: }, token);
26:
27: //create a Task with a CancellationToken
28: Task task2 = new Task(() =>
29: {
30: double sum = 0;
31: for (int i = 0; i < NUM_MAX; i++)
32: {
33: sum = sum + (2 * i + 1) * (i + 1) * i / 6;
34: }
35: }, token);
36:
37: task1.Start();
38: task2.Start();
39:
40: Console.WriteLine("Cancelling all the tasks");
41: //cancel all the tasks
42: tokenSource2.Cancel();
43:
44: Console.ReadLine();
45: }