欢迎光临
我的个人博客网站

.NET异步和多线程系列(六)- async/await

本文是.NET异步和多线程系列的第六章,本章主要对之前介绍过的async/await做一些补充说明。

下面我们直接来看下代码和运行结果:

using System; using System.Threading; using System.Threading.Tasks;  namespace MyAsyncAwait {     /// <summary>     /// await/async 是C#保留关键字,通常是成对出现,语法糖。     ///      /// 主线程调用async/await方法,主线程遇到await返回执行后续动作,     /// await后面的代码会等着Task任务的完成后再继续执行     /// 其实就像把await后面的代码包装成一个ContinueWith的回调动作     /// 然后这个回调动作可能是Task线程,也可能是新的子线程,也可能是主线程     ///      /// 一个async方法,如果没有返回值,可以方法声明返回Task     /// await/async能够用同步的方式编写代码,但又是非阻塞的。     ///      /// async方法在编译后会生成一个状态机(实现了IAsyncStateMachine接口)     /// </summary>     class Program     {         static void Main(string[] args)         {             Console.WriteLine($"当前主线程开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");             AwaitAsyncClass.TestShow();             Console.WriteLine($"当前主线程结束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");             Console.ReadKey();         }     }      /// <summary>     /// await/async关键字 语法糖     /// await/async 要么不用 要么用到底     /// </summary>     public class AwaitAsyncClass     {         public static void TestShow()         {             Test();         }          private async static Task Test()         {             Console.WriteLine($"Test开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");              Task<long> t = SumAsync();             Console.WriteLine($"遇到await主线程回来干活了 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");              {                 long lResult = await t;  //await后面的代码会由线程池的线程执行,非阻塞。                 Console.WriteLine($"最终得到的lResult={lResult}");             }              {                 //t.Wait(); //主线程等待Task的完成,阻塞的                 //long lResult = t.Result; //访问Result,主线程等待Task的完成,阻塞的,效果跟t.Wait()一样                 //Console.WriteLine($"最终得到的lResult={lResult}");             }              Console.WriteLine($"Test结束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");         }          /// <summary>         /// 带返回值的Task         /// 要使用返回值就一定要等子线程计算完毕         /// </summary>         private static async Task<long> SumAsync()         {             Console.WriteLine($"SumAsync start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");             long result = 0;              //await后面的代码会等着Task任务的完成后再继续执行             //其实就像把await后面的代码包装成一个ContinueWith的回调动作             //然后这个回调动作可能是Task线程,也可能是新的子线程,也可能是主线程             await Task.Run(() =>             {                 for (int k = 0; k < 2; k++)                 {                     Console.WriteLine($"SumAsync 第1个 await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");                     Thread.Sleep(1000);                 }                 for (long i = 0; i < 999_999_999; i++)                 {                     result += i;                 }             });              Console.WriteLine($"SumAsync 第1个 await Task.Run的后续任务开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");             await Task.Run(() =>             {                 for (int k = 0; k < 2; k++)                 {                     Console.WriteLine($"SumAsync 第2个 await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");                     Thread.Sleep(1000);                 }                 for (long i = 0; i < 999_999_999; i++)                 {                     result += i;                 }             });              Console.WriteLine($"SumAsync 第2个 await Task.Run的后续任务开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");             await Task.Run(() =>             {                 for (int k = 0; k < 2; k++)                 {                     Console.WriteLine($"SumAsync 第3个 await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");                     Thread.Sleep(1000);                 }                 for (long i = 0; i < 999_999_999; i++)                 {                     result += i;                 }             });              Console.WriteLine($"SumAsync end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");             return result;         }     } }

运行结果如下:

.NET异步和多线程系列(六)- async/await

仔细观察结果会发现

  主线程调用async/await方法,主线程遇到await后会返回执行后续动作;

  await后面的代码会等着Task任务的完成后再继续执行,其实就像把await后面的代码包装成一个ContinueWith的回调动作;

  然后这个回调动作可能是Task线程,也可能是新的子线程,也可能是主线程;

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

下面我们调整下Test方法后再运行(红色的为调整部分):

private async static Task Test() {     Console.WriteLine($"Test开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");      Task<long> t = SumAsync();     Console.WriteLine($"遇到await主线程回来干活了 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");      {         //long lResult = await t;  //await后面的代码会由线程池的线程执行,非阻塞。         //Console.WriteLine($"最终得到的lResult={lResult}");     }      {         //t.Wait(); //主线程等待Task的完成,阻塞的         long lResult = t.Result; //访问Result,主线程等待Task的完成,阻塞的,效果跟t.Wait()一样         Console.WriteLine($"最终得到的lResult={lResult}");     }      Console.WriteLine($"Test结束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); }

调整后运行结果如下:

.NET异步和多线程系列(六)- async/await

仔细观察结果会发现

  访问Result,主线程会等待Task的完成,阻塞的。

其实async方法在编译后会生成一个状态机(实现了IAsyncStateMachine接口),有兴趣的可以自行去了解下。

至此本文就介绍完了,有兴趣的还可以看下我之前写过一篇也是关于async/await的文章:https://www.cnblogs.com/xyh9039/p/11391507.html

 

Demo源码:

链接:https://pan.baidu.com/s/1jnG5IpteuKCdmF6-tr--cA  提取码:3onm

此文由博主精心撰写转载请保留此原文链接:https://www.cnblogs.com/xyh9039/p/13622122.html

版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!

赞(0) 打赏
未经允许不得转载:张拓的天空 » .NET异步和多线程系列(六)- async/await
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

专业的IT技术经验分享 更专业 更方便

联系我们本站主机

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏