使用线程池使得创建线程已经很简单了,但是使用线程池不支持线程的取消,完成和失败通知等交互操作,为了解决这些问题,.net 4.0带来了TPL(Task Parallel Library)任务并行库,下面就来总结下Task的使用。

创建和运行任务

在.net 4.0下使用task创建一个线程非常简单,有两种方式,如下代码:

 1 namespace ConsoleApplication19
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //方法1
 8             var task1 = new Task(() => 
 9             {
10                 Console.WriteLine("Create and start task!");
11             });
12             task1.Start();
13 
14             //方法2
15             Task.Factory.StartNew(() => 
16             {
17                 Console.WriteLine("Task factory start new task!");
18             });
19 
20             Console.ReadKey();
21         }
22     }
23 }
View Code

 

输出结果:

需要注意的是:task也是基于线程池的,所以这两个任务的执行顺序是不固定的。 

取消任务

 创建一个新的任务之后,我们随时都可以取消它,取消方法如下代码:

 

 

 1 namespace ConsoleApplication20
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Console.WriteLine("Main thread starting...");
 8 
 9             var cts = new CancellationTokenSource();
10             var task1 = Task.Factory.StartNew(() =>
11             {
12                 TaskAction(cts.Token);
13             });
14 
15             Thread.Sleep(3000);
16             Console.WriteLine(string.Format("current task status::{0}", task1.Status));
17 
18             //取消任务
19             cts.Cancel();
20             Console.WriteLine("start cancel task!");
21             for (int i = 0; i < 5; i++)
22             {
23                 Thread.Sleep(500);
24                 Console.WriteLine(string.Format("current task status::{0}", task1.Status));
25             }
26 
27             Console.WriteLine("Main thread completed!");
28             Console.ReadKey();
29         }
30 
31         public static void TaskAction(CancellationToken token)
32         {
33             Console.WriteLine("Sub thread starting...");
34 
35             while (true)
36             {
37                 Thread.Sleep(1000);
38                 if (token.IsCancellationRequested)
39                 {
40                     Console.WriteLine("Sub thread be cancelled!");
41                     return;
42                 }
43                 Console.WriteLine("Sub thread is running!");
44             }
45         }
46 
47     }
48 }
View Code

 输出结果:

创建任务集合并输出结果 

如下代码:

 1 namespace ConsoleApplication21
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //创建任务集合并输出结果
 8             var tasks = new List<Task<string>>();
 9 
10             var task1 = Task.Factory.StartNew<string>(() => 
11             {
12                 Console.WriteLine("task1 running on thread id:"+ Thread.CurrentThread.ManagedThreadId);
13                 return "task1";
14             });
15             tasks.Add(task1);
16 
17             var task2 = Task.Factory.StartNew<string>(() =>
18             {
19                 Console.WriteLine("task2 running on thread id:" + Thread.CurrentThread.ManagedThreadId);
20                 return "task2";
21             });
22             tasks.Add(task2);
23 
24             var task3 = Task.Factory.StartNew<string>(() => 
25             {
26                 Console.WriteLine("task3 running on thread id:" + Thread.CurrentThread.ManagedThreadId);
27                 return "task3";
28             });
29             tasks.Add(task3);
30 
31             //输出结果
32             foreach (var item in tasks)
33             {
34                 Console.WriteLine(item.Result);//调用Task的Result方法相当于调用了Task.WaitAll(tasks.ToArray());
35             }
36 
37             Console.ReadKey(); 
38         }
39     }
40 }

 

输出结果:

这里要注意2点:

1,每个任务会开启一个新的线程,并且运行顺序不固定。

2,Task.Result相当于调用了Wait方法,等待异步任务完成。

多任务的串行化

 如下代码:

 1 namespace ConsoleApplication22
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //多任务的串行化
 8             var task1 = Task.Factory.StartNew(() => 
 9             {
10                 Console.WriteLine("start task1...");
11                 Console.WriteLine("current thread id:"+ Thread.CurrentThread.ManagedThreadId);
12             });
13 
14             var task2 = task1.ContinueWith((item) => 
15             {
16                 Console.WriteLine("start task2...");
17                 Console.WriteLine("current thread id:" + Thread.CurrentThread.ManagedThreadId);
18             });
19 
20             var task3 = task2.ContinueWith((item)=>
21             {
22                 Console.WriteLine("start task3...");
23                 Console.WriteLine("current thread id:" + Thread.CurrentThread.ManagedThreadId);
24             });
25 
26             Console.ReadKey();
27         }
28     }
29 }

 输出结果:

注意,多任务串行化后,就相当于顺序执行了,而且有可能使用的是同一个线程,从上图的thread id就可以看出来。

多任务等待执行完成

如下代码:

 1 namespace ConsoleApplication23
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //多任务等待执行完成
 8             var tasks = new List<Task<string>>();
 9 
10             var task1 = Task.Factory.StartNew<string>(() => 
11             {
12                 Console.WriteLine("task1");
13                 return "task1";
14             });
15             tasks.Add(task1);
16 
17             var task2 = Task.Factory.StartNew<string>(() => 
18             {
19                 Console.WriteLine("task2");
20                 return "task2";
21             });
22             tasks.Add(task2);
23 
24             var task3 = Task.Factory.StartNew<string>(() => 
25             {
26                 Console.WriteLine("task3");
27                 return "task3";
28             });
29             tasks.Add(task3);
30 
31             //等待所有任务完成
32             Task.WaitAll(tasks.ToArray());
33 
34             //等价于下面的调用
35             //foreach (var item in tasks)
36             //{
37             //    item.Result
38             //}
39 
40             Console.ReadKey();
41         }
42     }
43 }

 

输出结果:

需要注意的是,如果是有返回值的task,可以使用Task.Result获取返回值的同时,也在等待Task执行完成,相当于调用了Task.Wait方法。

创建子任务

如下代码:

 1 namespace ConsoleApplication24
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //创建子任务
 8             var parentTask = Task.Factory.StartNew(() => 
 9             {
10                 Console.WriteLine("parent task!");
11                 var childTask = Task.Factory.StartNew(() => 
12                 {
13                     Console.WriteLine("child task!");
14                 }, TaskCreationOptions.AttachedToParent);
15             });
16 
17             Console.ReadKey();
18         }
19     }
20 }

 

输出结果: