2020年9月6日星期日

.NET异步和多线程系列(六)

本系列将和大家分享.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;  } }}

运行结果如下:

仔细观察结果会发现:

  主线程调用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}");}

调整后运行结果如下:

仔细观察结果会发现:

  访问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

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

.NET异步和多线程系列(六)ChannelAdvisor携手拉丁美洲最大电商平台Mercadolibre CBT诚意来深招商!亚马逊运营全攻略分享大会打折网捂脸表情被抢注,遭殃的不只是卖家,还有腾讯?美国消费者常用的11个玩具购物网站大盘点!(精品分析)亚马逊美国站折叠雨伞类目市场调查数据报告实用干货:外贸人必懂这些航贸英语短句!eBay在美国启动全新的支付管理方案!

没有评论:

发表评论

注意:只有此博客的成员才能发布评论。