zoukankan      html  css  js  c++  java
  • AwaitAsync(异步和多线程)

    参考了一些大佬写的文章:

    https://www.cnblogs.com/yilezhu/p/10555849.html这个大佬写的文章,我还是很喜欢的

    https://www.cnblogs.com/mushroom/p/4575417.html

    https://blog.csdn.net/dyllove98/article/details/9735955这篇文章是讨论在.NET中使用进程内COM组件时的公寓模型,以一个示例直观演示STAThread和MTAThread的作用和区别。

     

    C#5.0,.NET Framework4.5

    async/await是语法糖,本身就跟编译器提供的功能。

    在winform中,是一个STAThread

     在winform中使用await/async偶尔会出现一些意外,所以不建议在winform中使用await/async

      await/async关键字,在任何一个方法都可以增加async,await放在Task前面,一般成对出现,只有async是没有意义的,有警告,只有await的时候会报错,编译直接报错,await/async要么不用,要么用到底。  

      主线程调用async/await方法,主线程遇到await返回只能后续动作,await后面的代码会等着task任务完成后再继续执行,await是主线程完成的,其实就像是把await后面的代码包装成一个continue的回调动作,然后这个回调动作也可能是task线程,也可能是新的子线程,也可能是主线程。

      一个async方法,如果没有返回值,可以方法声明返回Task

     private static async Task<long> SumAsync()
     {
         Console.WriteLine($"SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
         long result = 0;
    
         await Task.Run(() =>
         {
             for (int k = 0; k < 10; k++)
             {
                 Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                 Thread.Sleep(1000);
             }
             for (long i = 0; i < 999_999_999; i++)
             {
                 result += i;
             }
         });
    
         Console.WriteLine($"SumFactory 111   end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
         await Task.Run(() =>
         {
             for (int k = 0; k < 10; k++)
             {
                 Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                 Thread.Sleep(1000);
             }
             for (long i = 0; i < 999999999; i++)
             {
                 result += i;
             }
         });
    
         Console.WriteLine($"SumFactory 111   end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    
         await Task.Run(() =>
         {
             for (int k = 0; k < 10; k++)
             {
                 Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                 Thread.Sleep(1000);
             }
    
             for (long i = 0; i < 999999999; i++)
             {
                 result += i;
             }
         });
    
         Console.WriteLine($"SumFactory 111   end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    
         return result;
     }
    Task<long> t = SumAsync();
    Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");

     有了await之后,在这个方法中,代码是按照顺序从上往下执行的,但是,为什么不直接写一个同步方法,还要写await呢?

      如果不写await的话,Task.Run()会开启一个线程,不会足额色主线程,这样在最后的结果result就是0了。

    await/async能够用同步的方式编写代码,但是又是非阻塞的。

    原理探究和使用建议:

     public class AwaitAsyncILSpy
     {
         public static void Show()
         {
             Console.WriteLine($"start1 {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
             Async();
             Console.WriteLine($"aaa2 {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
         }
         public static async void Async()
         {
             Console.WriteLine($"ddd5 {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
             await Task.Run(() =>
             {
                 Thread.Sleep(500);
                 Console.WriteLine($"bbb3 {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
             });
             Console.WriteLine($"ccc4 {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
         }
     }
     AwaitAsyncLibrary.AwaitAsyncILSpy.Show();
     Console.WriteLine("hello word!");

    这样的代码,输出的顺序是是什么?

     await/async能够用同步的方式编写代码,但又是非阻塞的

    async方法在编译之后会生成一个状态机(实现了IAsyncStateMachine接口)

    状态机:初始化状态----执行就修改状态1-----再执行就修改状态变为0-----执行就修改状态变为1----如果出现其他状态就结束了。

    就像是红绿灯那样,永远的死循环下去。

      async方法里面的逻辑其实都放在了MoveNext----主线程new一个状态机1-----主线程调用MoveNext-----指向了await之前的东西----启动Task----主线程改状态为0----回去干自己的事了-----子线程Movenext----状态又回归-1了-----再执行后续的逻辑------如果需要还可以继续循环。

  • 相关阅读:
    MKMapVIew学习系列2 在地图上绘制出你运行的轨迹
    WPF SDK研究 Intro(6) WordGame1
    WPF SDK研究 Intro(3) QuickStart3
    WPF SDK研究 Layout(1) Grid
    WPF SDK研究 目录 前言
    WPF SDK研究 Intro(7) WordGame2
    WPF SDK研究 Layout(2) GridComplex
    对vs2005创建的WPF模板分析
    WPF SDK研究 Intro(4) QuickStart4
    《Programming WPF》翻译 第6章 资源
  • 原文地址:https://www.cnblogs.com/taotaozhuanyong/p/11560145.html
Copyright © 2011-2022 走看看