多線程(4)Task


 

  使用線程池使得創建線程已經很簡單了,但是使用線程池不支持線程的取消,完成和失敗通知等交互操作,為了解決這些問題,.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 }

 

輸出結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM