zoukankan      html  css  js  c++  java
  • 第八节: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             }

  • 相关阅读:
    vb笔记
    linux学习笔记
    linnux--shell
    # 用类来封装动态数组:分文件编写
    面向对象
    c++2
    c++1
    答疑:指针数组字符串
    文件操作
    用函数封装实现对一个数组增删改查
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/8256760.html
Copyright © 2011-2022 走看看