• .Net 多线程 异步编程 Await、Async和Task


    await和async简介

      await和async是在C#5中引入,并且在.NetFramewor4.5以及.NetCore中进行了支持。主要是解决性能瓶颈,并且增强系统的响应能力。
    图片

    msdn关于await以及async运行机理的描述

    以上demo详细的描述了使用await时程序的运行机制,需要注意的以下几点:

    • 第五步:执行完成后如果发现下一步还有await即设置了中断点,此时命令会直接跳出此方法即执行6,换句话说,await表达式执行时暂停并不构成方法退出,只会导致 finally 代码块不运行
    • 第七步:当执行当getStringTask返回结果(第七步)及await等待方法执行完成开始执行后续操作时(8)此时的线程已经和第四步执行的线程不同编号了,但是此时4所在线程上下文中的AsyncLocal变量会被复制到await返回后的线程上下文中。详细参照https://www.cnblogs.com/liyong-blackStone/p/10270526.html
    • async 和 await 关键字不会创建其他线程。 因为异步方法不会在其自身线程上运行,因此它不需要多线程.

    Task简介

    Task类的表示单个操作不会返回一个值,通常以异步方式执行Task对象是一种的中心思想基于任务的异步模式。首次引入.NET Framework 4 中。
    Task可以通过以下几种方式开始执行:

                Task.Run(() =>
                {
                    Console.WriteLine("无返回值委托");
                });
                Task.Run<int>(() =>
                {
                    Console.WriteLine("带返回值委托");
                    return 1;
                });
                Task t = new Task(() =>
                {
                    Console.WriteLine("声明一个Task可以后续通过t.run执行");
                });
                TaskFactory factory = new TaskFactory();
                factory.StartNew<int>(() =>
                {
                    Console.WriteLine("通过TaskFactory执行");
                    return 1;
                });
                Task t4 = new Task(() =>
                {
                    Console.WriteLine("同步执行");
                });
                // 同步执行
                t4.RunSynchronously();
    

    task的执行方式这里不多做介绍,下面主要说下Task的异常处理。

    异步方法内部的异常处理

    .Net中异步方法由 async修饰符标记,通常包含一个或多个await表达式或语句。await表达式将await运算符应用于 Task 或Task。由于在异步方法中通常会存在多个线程,而子线程中的异常信息不能自动的抛到主线程上,所以要想在主线程上获得子线程的异常信息,需要借助于返回的task这个对象。以下为Msdn给出的一段示例代码:

    public async Task DoSomethingAsync()
    {
        Task<string> theTask = DelayAsync();
    
        try
        {
            string result = await theTask;
            Debug.WriteLine("Result: " + result);
        }
        catch (Exception ex)
        {
            Debug.WriteLine("Exception Message: " + ex.Message);
        }
        Debug.WriteLine("Task IsCanceled: " + theTask.IsCanceled);
        Debug.WriteLine("Task IsFaulted:  " + theTask.IsFaulted);
        if (theTask.Exception != null)
        {
            Debug.WriteLine("Task Exception Message: "
                + theTask.Exception.Message);
            Debug.WriteLine("Task Inner Exception Message: "
                + theTask.Exception.InnerException.Message);
        }
    }
    
    private async Task<string> DelayAsync()
    {
        await Task.Delay(100);
    
        // Uncomment each of the following lines to
        // demonstrate exception handling.
    
        //throw new OperationCanceledException("canceled");
        //throw new Exception("Something happened.");
        return "Done";
    }
    
    // Output when no exception is thrown in the awaited method:
    //   Result: Done
    //   Task IsCanceled: False
    //   Task IsFaulted:  False
    
    // Output when an Exception is thrown in the awaited method:
    //   Exception Message: Something happened.
    //   Task IsCanceled: False
    //   Task IsFaulted:  True
    //   Task Exception Message: One or more errors occurred.
    //   Task Inner Exception Message: Something happened.
    
    // Output when a OperationCanceledException or TaskCanceledException
    // is thrown in the awaited method:
    //   Exception Message: canceled
    //   Task IsCanceled: True
    //   Task IsFaulted:  False
    

    对于异步线程的执行结果,最多有三种情况

    • 正常执行结束:可以通过IsCompletedSuccessfully 属性表示任务正常结束,并成功执行。特别说明:IsCompleted为true只能表示执行完成,当任务处于三种最终状态之一: RanToCompletion, Faulted,或Canceled。时他都为true
    • 发生异常:发生异常时,可以通过返回的task对象中的IsFaulted属性判断,为true时表示发生异常,如果要获取具体的异常信息,可以通过以下以下方式获取
        task.Exception.InnerException.Message
    
    • 异步线程被取消:异步线程被取消时task中的IsCanceled属性会被设置为true
      了解取消任务可以参考msdn示例:
    using System;
    using System.Threading;
    using System.Threading.Tasks;
    
    public class Example
    {
       public static void Main()
       {
          // Create a cancellation token and cancel it.
          var source1 = new CancellationTokenSource();
          var token1 = source1.Token;
          source1.Cancel();
          // Create a cancellation token for later cancellation.
          var source2 = new CancellationTokenSource();
          var token2 = source2.Token;
           
          // Create a series of tasks that will complete, be cancelled, 
          // timeout, or throw an exception.
          Task[] tasks = new Task[12];
          for (int i = 0; i < 12; i++)
          {
              switch (i % 4) 
              {
                 // Task should run to completion.
                 case 0:
                    tasks[i] = Task.Run(() => Thread.Sleep(2000));
                    break;
                 // Task should be set to canceled state.
                 case 1:   
                    tasks[i] = Task.Run( () => Thread.Sleep(2000),
                             token1);
                    break;         
                 case 2:
                    // Task should throw an exception.
                    tasks[i] = Task.Run( () => { throw new NotSupportedException(); } );
                    break;
                 case 3:
                    // Task should examine cancellation token.
                    tasks[i] = Task.Run( () => { Thread.Sleep(2000); 
                                                 if (token2.IsCancellationRequested)
                                                    token2.ThrowIfCancellationRequested();
                                                 Thread.Sleep(500); }, token2);   
                    break;
              }
          }
          Thread.Sleep(250);
          source2.Cancel();
           
          try {
             Task.WaitAll(tasks);
          }
          catch (AggregateException ae) {
              Console.WriteLine("One or more exceptions occurred:");
              foreach (var ex in ae.InnerExceptions)
                 Console.WriteLine("   {0}: {1}", ex.GetType().Name, ex.Message);
           }   
    
          Console.WriteLine("
    Status of tasks:");
          foreach (var t in tasks) {
             Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status);
             if (t.Exception != null) {
                foreach (var ex in t.Exception.InnerExceptions)
                   Console.WriteLine("      {0}: {1}", ex.GetType().Name,
                                     ex.Message);
             }
          }
       }
    }
    // The example displays output like the following:
    //   One or more exceptions occurred:
    //      TaskCanceledException: A task was canceled.
    //      NotSupportedException: Specified method is not supported.
    //      TaskCanceledException: A task was canceled.
    //      TaskCanceledException: A task was canceled.
    //      NotSupportedException: Specified method is not supported.
    //      TaskCanceledException: A task was canceled.
    //      TaskCanceledException: A task was canceled.
    //      NotSupportedException: Specified method is not supported.
    //      TaskCanceledException: A task was canceled.
    //   
    //   Status of tasks:
    //      Task #13: RanToCompletion
    //      Task #1: Canceled
    //      Task #3: Faulted
    //         NotSupportedException: Specified method is not supported.
    //      Task #8: Canceled
    //      Task #14: RanToCompletion
    //      Task #4: Canceled
    //      Task #6: Faulted
    //         NotSupportedException: Specified method is not supported.
    //      Task #7: Canceled
    //      Task #15: RanToCompletion
    //      Task #9: Canceled
    //      Task #11: Faulted
    //         NotSupportedException: Specified method is not supported.
    //      Task #12: Canceled
    
  • 相关阅读:
    3.2.1 webpack-dev-server的使用
    打印预览及打印
    2.1.8 webpack的环境
    常用docker 启动
    github镜像
    Log解析
    【Bzoj4555】【Luogu P4091】求和(NTT)
    【Bzoj3527】【Luogu3338】[Zjoi2014]力(FFT)
    FFT实现高精度乘法
    Bzoj 2190 仪仗队(莫比乌斯反演)
  • 原文地址:https://www.cnblogs.com/liyong-blackStone/p/10276769.html
Copyright © 2020-2023  润新知