异步async与await的简单探究

Posted guolinjiang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异步async与await的简单探究相关的知识,希望对你有一定的参考价值。

  在学习.net core的过程中,到处见到异步的使用,Task、async、await随处可见。有点疑惑,就去了解了下这个过程是怎样的。

下面是一段代码,去看看是怎么执行的吧。

一、看看异步执行的方式

static void Main(string[] args)
{

  Console.WriteLine("我是主线程:我的ID是:" + Thread.CurrentThread.ManagedThreadId);
  Console.WriteLine();

  TestAsync();

  Console.WriteLine("不等异步完成我先执行了哈,我的ID是:" + Thread.CurrentThread.ManagedThreadId);
  Console.ReadKey();

}
/// <summary>
/// 异步方法
/// </summary>
/// <returns></returns>
static async Task TestAsync()
{
     Console.WriteLine("我是TestAsync,调用我的线程ID是:" + Thread.CurrentThread.ManagedThreadId);
     await Task.Run(() => {
       Console.WriteLine("我是在TestAsync中开启的线程,ID是:" + Thread.CurrentThread.ManagedThreadId);
     });
     Console.WriteLine("TestAsync开启的线程执行完后,此时的线程ID为:" + Thread.CurrentThread.ManagedThreadId);
}

技术分享图片

  我们看到,主线程ID是1,然后调用TestAsync方法,注意在Main方法中,调用TestAsync我们没有使用await,因为在Main方法中不支持async。

主线程调用TestAsync方法,进到TestAsync之后,打印出调用TestAsync方法的线程的ID。然后遇到Task.Run开启新的线程,ID为3。Task.Run之前有await,

注意:await会阻塞当前线程,就是ID为3的线程,并且释放调用TestAsync方法的线程,也即是主线程(ID为1),这个时候我们看到"不等异步完成我先执行了哈,我的ID是:1"

输出在"TestAsync开启的线程执行完后,此时的线程ID为:4"之前。这就说明了,TestAsync方法中await释放了主线程,同时Task.Run开启了一个新的线程。

Task.Run开启的线程是从线程池中取出的空闲线程。我运行几次,发现最后一个输出的结果不一样。如下图:技术分享图片

这应该说明,Task.Run开启线程后,await后的代码,是会重新开启一个线程去执行的。

二、看看await是怎么阻塞之后的代码的。

static void Main(string[] args)
{

  Console.WriteLine("我是主线程:我的ID是:" + Thread.CurrentThread.ManagedThreadId);
  Console.WriteLine();

  TestAsync();

  Console.WriteLine("不等异步完成我先执行了哈,我的ID是:" + Thread.CurrentThread.ManagedThreadId);
  Console.ReadKey();

}
/// <summary>
/// 异步方法
/// </summary>
/// <returns></returns>
static async Task TestAsync()
{
    Console.WriteLine("我是TestAsync,调用我的线程ID是:" + Thread.CurrentThread.ManagedThreadId);
    await TestAsync2();
    Console.WriteLine("我被阻塞了,在TestAsync2执行之后才会执行,现在的线程ID是:" + Thread.CurrentThread.ManagedThreadId);
    await Task.Run(() => {
          Console.WriteLine("我是在TestAsync中开启的线程,ID是:" + Thread.CurrentThread.ManagedThreadId);
    });
    Console.WriteLine("TestAsync开启的线程执行完后,此时的线程ID为:" + Thread.CurrentThread.ManagedThreadId);
}
static async Task TestAsync2()
{
    Console.WriteLine();
    Console.WriteLine("我是TestAsync2,调用我的线程ID是:" + Thread.CurrentThread.ManagedThreadId);
    await Task.Run(() => {
       Console.WriteLine("我是在TestAsync2中开启的线程,ID是:" + Thread.CurrentThread.ManagedThreadId);
       int num = 0;
       for (int i = 0; i < 1000000; i++)
       {
           num += 1;
       }
       Console.WriteLine($"在TestAsync2中执行一个耗点儿时间的操作,num的值是{num}");
    });
 }

技术分享图片

我们看到在TestAsync中调用TestAsync2前面加了await,"我被阻塞了,在TestAsync2执行之后才会执行,现在的线程ID是:3"

在TestAsync2方法执行之后,才输出。并且这个时候主线程被释放掉了,去输出"不等异步完成我先执行了哈,我的ID是:1"。

 

好了,暂时就理解了这么多,肯定有不对的地方,欢迎大家指正,时间不早了,早点休息,做个佛系养生的程序员

以上是关于异步async与await的简单探究的主要内容,如果未能解决你的问题,请参考以下文章

Async/await:让异步编程更简单

js异步回调Async/Await与Promise区别 新学习使用Async/Await

异步编程之 async 和 await

js异步回调Async/Await与Promise区别

promise与async和await的区别

ES7的Async/Await的简单理解