第八節:Task的各類Task 返回值以及通用線程的異常處理方案。


一. Task的各種返回值-Task<TResult> 

PS: 在前面章節,我們介紹了Task類開啟線程、線程等待、線程延續的方式,但我們並沒有關注這些方式的返回值,其實他們都是有返回值的Task<TResult>,然后可以通過Task的實例調用Result屬性來獲取這個返回值。

  下面我們分三類來介紹:

  ①:線程開啟類的返回值, 使用Task<TResult>接受,或者直接使用Task接受,通過 實例.Result 來獲取返回值。這里的線程開啟類有多種,eg: Task.Run()、 task.start()、 Task.Factory.StartNew() 等。

  ②:線程延續類的返回值. eg:ContinueWith。

  ③:線程條件延續類的返回值. eg:WhenAll和WhenAny。

 1. 線程開啟類的返回值

1             {
2                 Task<string> task1 = Task.Factory.StartNew(() =>
3                 {
4                     Console.WriteLine("我是子線程哦");
5                     return "ok";
6                 });
7                 task1.Wait();
8                 Console.WriteLine("我是主線程,我要讀取子線程task1的返回值為:{0}", task1.Result);
9             }

2.  線程延續類的返回值

 1             {
 2                 Task<int> task1 = Task.Run(() =>
 3                   {
 4                       Console.WriteLine("我是子線程1哦");
 5                       return 2;
 6                   });
 7 
 8                 var task2 = task1.ContinueWith((t) =>
 9                 {
10                     Console.WriteLine("我是子線程2哦");
11 
12                     //這里的t代表 task1
13                     var num = t.Result + 2;
14                     return num.ToString();
15                 });
16 
17                 task2.Wait();
18                 Console.WriteLine("我是主線程,我要讀取子線程task1的返回值為:{0}", task1.Result);
19                 Console.WriteLine("我是主線程,我要讀取子線程task2的返回值為:{0}", task2.Result);
20             }

3. 線程條件延續類

 1  {
 2                 Task<int> task1 = Task.Run(() =>
 3                 {
 4                     Console.WriteLine("我是子線程1哦");
 5                     return 1;
 6                 });
 7                 Task<int> task2 = Task.Run(() =>
 8                 {
 9                     Console.WriteLine("我是子線程2哦");
10                     return 2;
11                 });
12 
13                 var task = Task.WhenAny(new Task<int>[2] { task1, task2 });
14                 task.Wait();
15 
16                 //下面的值可能是1,也可能是2
17                 Console.WriteLine("我是主線程,我要讀取子線程task的返回值為:{0}", task.Result.Result);
18  }

 

二. 通用線程異常處理方案

1.  背景:我們想達到一個目的,當同時開啟多個線程的時候,其中一個線程報錯,不影響其他線程的執行,並且能把錯誤記下來。

2.   解決方案:多重try-catch,整個外側主線程一個try-catch,然后線程執行業務再用一個try-catch包裹起來。

常規方式捕獲異常:

 1             {
 2                 try
 3                 {
 4                     for (int i = 0; i < 5; i++)
 5                     {
 6                         string name = string.Format("name{0}", i);
 7                         var task = Task.Run(() =>
 8                         {
 9                             try
10                             {
11                                 //模擬某個線程出錯
12                                 if (name == "name2")
13                                 {
14                                     throw new Exception(string.Format("線程執行失敗,i={0}", name));
15                                 }
16                                 else
17                                 {
18                                     Console.WriteLine(string.Format("線程執行執行成功,i={0}", name));
19                                 }
20                             }
21                             catch (Exception ex)
22                             {
23                                 Console.WriteLine(ex.Message);
24                             }
25 
26                         });
27                         taskList.Add(task);
28                     }
29                     Task.WaitAll(taskList.ToArray());
30                 }
31                 catch (Exception ex)
32                 {
33                     Console.WriteLine(ex.Message);
34 
35                 }
36             }

運行結果:我們發現所有的線程均執行完畢,且name2執行失敗,並捕獲。

 

補充一下:通過 AggregateException 類來捕獲異常。

 

 1             {
 2                 try
 3                 {
 4                     for (int i = 0; i < 5; i++)
 5                     {
 6                         string name = string.Format("name{0}", i);
 7                         var task = Task.Run(() =>
 8                         {
 9                             throw new Exception(string.Format("線程執行失敗,i={0}", name));
10                         });
11                         taskList.Add(task);
12                     }
13                     Task.WaitAll(taskList.ToArray());
14                 }
15                 catch (AggregateException aes)
16                 {
17                     foreach (var item in aes.InnerExceptions)
18                     {
19                         Console.WriteLine(item.Message);
20                     }
21                 }
22             }

 

 

 

 

 


免責聲明!

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



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