第八节:Task的各类Task<TResult>返回值以及通用线程的异常处理方案。

一. 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             }

 

 

 

 

 

posted @ 2018-01-10 08:01  Yaopengfei  阅读(3708)  评论(1编辑  收藏  举报