• AwaitAsync(异步和多线程)


    原文:https://www.cnblogs.com/taotaozhuanyong/p/11560145.html

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

    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了-----再执行后续的逻辑------如果需要还可以继续循环。

  • 相关阅读:
    如何实现Echart不刷新页面,多语言切换下的地图数据重新加载,api请求数据加载,soketed数据实时加载
    web开发中各种宽高
    http请求方式和传递数据类型
    Hexo之傻瓜攻略
    SQL2008 R2安装功能选择
    Windows Server2012 R2中安装SQL Server2008
    用户权限管理数据库设计
    C#生成缩略图 (通用模式)
    CAD习题集
    菜鸟学习MVC实录:弄清项目各类库的作用和用法
  • 原文地址:https://www.cnblogs.com/zhang1f/p/11667116.html
Copyright © 2020-2023  润新知