c# await/async

异步多线程 :

await/async是一个语法糖,不是一个全新的异步多线程的使用方式。它本身不会产生新的线程,它是依托于Task存在,所以在实际程序运行过程中是有多线程的,这些多线程是有Task产生的。

如果一个方法没有返回值,可以用下面方法写,下面中的2个方法是等价的:

复制代码
    public async void NoReturn()
        {
            Console.WriteLine($"This is NoReturn Start {Thread.CurrentThread.ManagedThreadId}");
            await Task.Run(() =>
            {
                Console.WriteLine($"This is NoReturn Task Start {Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(2000);
                Console.WriteLine($"This is NoReturn Task End {Thread.CurrentThread.ManagedThreadId}");

            });
            Console.WriteLine($"This is NoReturn End {Thread.CurrentThread.ManagedThreadId}");
        }

        public async Task ReturnTask()
        {
            Console.WriteLine($"This is NoReturn Start {Thread.CurrentThread.ManagedThreadId}");
            await Task.Run(() =>
            {
                Console.WriteLine($"This is NoReturn Task Start {Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(2000);
                Console.WriteLine($"This is NoReturn Task End {Thread.CurrentThread.ManagedThreadId}");

            });
            Console.WriteLine($"This is NoReturn End {Thread.CurrentThread.ManagedThreadId}");
        }
复制代码

 

有没有await关键字其实是有区别的,

代码:

复制代码
public class AwaitAsyncClassNew
    {
        public void Show()
        {
            Console.WriteLine($"This is Main Start {Thread.CurrentThread.ManagedThreadId}");
            this.NoReturn(); 
            Console.WriteLine($"This is Main Start {Thread.CurrentThread.ManagedThreadId}");
        } 
        #region 无返回值
        public   void NoReturn()
        {
            Console.WriteLine($"This is NoReturn Start {Thread.CurrentThread.ManagedThreadId}");
              Task.Run(() =>
            {
                Console.WriteLine($"This is NoReturnTask Start {Thread.CurrentThread.ManagedThreadId}");
                 
                Console.WriteLine($"This is NoReturnTask End {Thread.CurrentThread.ManagedThreadId}");

            });
            Console.WriteLine($"This is NoReturn End {Thread.CurrentThread.ManagedThreadId}");
        }

        public async Task ReturnTask()
        {
            Console.WriteLine($"This is NoReturn Start {Thread.CurrentThread.ManagedThreadId}");
            await Task.Run(() =>
            {
                Console.WriteLine($"This is NoReturnTask Start {Thread.CurrentThread.ManagedThreadId}");
               
                Console.WriteLine($"This is NoReturnTask End {Thread.CurrentThread.ManagedThreadId}");

            });
            Console.WriteLine($"This is NoReturn End {Thread.CurrentThread.ManagedThreadId}");
        }
        #endregion 
    }
复制代码

 

此时show方法调用的是NoReturn方法,结果如下:

This is Main Start 1
This is NoReturn Start 1
This is NoReturn End 1
This is Main End 1
This is NoReturnTask Start 4
This is NoReturnTask End 4

 

 

从这个结果我们可以看出Task启用的是一个子线程4来运行方法,后续的操作都是主线程1来完成的。

代码:现在调用ReturnTask方法

复制代码
 public class AwaitAsyncClassNew
    {
        public void Show()
        {
            Console.WriteLine($"This is Main Start {Thread.CurrentThread.ManagedThreadId}");
            this.ReturnTask();
            Console.WriteLine($"This is Main End {Thread.CurrentThread.ManagedThreadId}");
        }
        #region 无返回值
        public void NoReturn()
        {
            Console.WriteLine($"This is NoReturn Start {Thread.CurrentThread.ManagedThreadId}");
            Task.Run(() =>
          {
              Console.WriteLine($"This is NoReturnTask Start {Thread.CurrentThread.ManagedThreadId}");
                //  Thread.Sleep(200);
                Console.WriteLine($"This is NoReturnTask End {Thread.CurrentThread.ManagedThreadId}");

          });
            Console.WriteLine($"This is NoReturn End {Thread.CurrentThread.ManagedThreadId}");
        }

        public async Task ReturnTask()
        {
            Console.WriteLine($"This is NoReturn Start {Thread.CurrentThread.ManagedThreadId}");//由调用线程执行
            await Task.Run(() =>
            {
               //内部操作由Task的子线程完成
                Console.WriteLine($"This is NoReturnTask Start {Thread.CurrentThread.ManagedThreadId}"); 
                Console.WriteLine($"This is NoReturnTask End {Thread.CurrentThread.ManagedThreadId}");

            }); //由调用线程执行,启动一个新线程来执行内部操作,然后回去干自己的事
            Console.WriteLine($"This is NoReturn End {Thread.CurrentThread.ManagedThreadId}");////由Task的子线程完成。

        }
        #endregion 

    }
复制代码

  

结果:

This is Main Start 1
This is NoReturn Start 1
This is NoReturnTask Start 4
This is NoReturnTask End 4
This is Main End 1
This is NoReturn End 4

 

加了await关键字之后执行结果就不一样了,在ReturnTask中执行到了await代码处之后就会跳出这个方法,直接继续执行,ReturnTask中的后续代码就会由Task的子线程来完成执行。

我们把NoReturn换一种写法: 

复制代码
 public void NoReturn()
        {
            Console.WriteLine($"This is NoReturn Start {Thread.CurrentThread.ManagedThreadId}");
            Task task = Task.Run(() =>
            { 
                Console.WriteLine($"This is NoReturnTask Start {Thread.CurrentThread.ManagedThreadId}"); 
                Console.WriteLine($"This is NoReturnTask End {Thread.CurrentThread.ManagedThreadId}");

            }); 
            task.ContinueWith(t => Console.WriteLine($"This is NoReturn End {Thread.CurrentThread.ManagedThreadId}"));
            //  Console.WriteLine($"This is NoReturn End {Thread.CurrentThread.ManagedThreadId}");
        }
复制代码

 

结果:

This is Main Start 1
This is NoReturn Start 1
This is Main End 1
This is NoReturnTask Start 4
This is NoReturnTask End 4
This is NoReturn End 5

 

首先我们要清楚ContinueWith这个方法是一个回调方法,是Task启动线程完成任务之后执行的方法。从这结果我们可以看出,This is NoReturn End 5不是由调用线程(如果不是多个线程的话,可以认为是主线程)执行的,而是Task的子线程执行的,其实结果和ReturnTask方法一样,都不是调用线程执行的,所以:可以认为执行完await这行代码之后的代码都是Task启动的子线程来完成的,也就是说将后面的代码包装成了一个回调方法。但是一定要注意的是执行这个回调方法的线程是有多种可能性的,很可能回调方法就是启动的那个子线程来执行,但也可能Task分配一个新的线程来完成这个后续操作,比如这里就是新分配了线程5来完成的。其实在前面说过的防止界面不卡,文件上传进度这些问题也都可以用这种形式来解决。

 多个await:

复制代码
    public async Task ReturnTask()
        {
            Console.WriteLine($"This is NoReturn Start {Thread.CurrentThread.ManagedThreadId}");//由调用线程执行
            Task task = Task.Run(() =>
            {
                //内部操作由Task的子线程完成
                Console.WriteLine($"This is NoReturnTask Start {Thread.CurrentThread.ManagedThreadId}");

                Console.WriteLine($"This is NoReturnTask End {Thread.CurrentThread.ManagedThreadId}");

            }); //由调用线程执行,启动一个新线程来执行内部操作
            await task;
            #region  这块区域可以看做是task的回调方法
            Console.WriteLine($"This is NoReturn End {Thread.CurrentThread.ManagedThreadId}");////由Task的子线程完成。

            Task task2 = Task.Run(() =>
          {
              //内部操作由Task的子线程完成
              Console.WriteLine($"This is NoReturnTask2 Start {Thread.CurrentThread.ManagedThreadId}");
              Console.WriteLine($"This is NoReturnTask2 End {Thread.CurrentThread.ManagedThreadId}");

          }); //由调用线程执行,启动一个新线程来执行内部操作
            await task2;//这行代码是由task1开启的子线程执行的,执行完这一行代码之后就返回,后续代码就是task2开启的子线程执行的了。
            #region task2的回调方法

            Console.WriteLine($"This is NoReturn2 End {Thread.CurrentThread.ManagedThreadId}");////由Task的子线程完成。 
            #endregion 
            #endregion
        }
复制代码

 

结果:

复制代码
This is Main Start 1
This is NoReturn Start 1
This is NoReturnTask Start 4
This is NoReturnTask End 4
This is Main End 1
This is NoReturn End 4
This is NoReturnTask2 Start 5
This is NoReturnTask2 End 5
This is NoReturn2 End 5
复制代码

 

从结果就可以看到NoReturn2和NoReturnTask2都是由线程5执行的,但是由于执行回调方法的不确定性,所以多次调用的话NoReturn2可能就是另一个线程来执行回调了。我们常说的用同步编码的方式来写异步就是用await/async这种形式来写。因为这种形式在使用await之后当前线程可以继续执行后续代码,task开启的子线程也可以继续执行其他方法。

有返回值的写法:

复制代码
     #region 有返回值
        public async Task<long> ReturnLongAwait()
        {
            Console.WriteLine($"This is ReturnLongAwait Start {Thread.CurrentThread.ManagedThreadId}");
            long result = 0;
            Task<long> task = Task.Run(() =>
             {
                 Console.WriteLine($"This is ReturnLongAwait Task Start {Thread.CurrentThread.ManagedThreadId}");
                 for (int i = 0; i < 1000000; i++)
                 {
                     result += i;
                 }
                 Console.WriteLine($"This is ReturnLongAwait Task End {Thread.CurrentThread.ManagedThreadId}");
                 return result;
             });
            await task;
            Console.WriteLine($"This is ReturnLongAwait End {Thread.CurrentThread.ManagedThreadId}");
            return result;
        }

        public long ReturnLong()
        {
            Console.WriteLine($"This is ReturnLong Start {Thread.CurrentThread.ManagedThreadId}");
            long result = 0;
            Task.Run(() =>
          {
              Console.WriteLine($"This is ReturnLong Task Start {Thread.CurrentThread.ManagedThreadId}");
              for (int i = 0; i < 1000000; i++)
              {
                  result += i;
              }
              Console.WriteLine($"This is ReturnLong Task End {Thread.CurrentThread.ManagedThreadId}");
              return result;
          });

            Console.WriteLine($"This is ReturnLong End {Thread.CurrentThread.ManagedThreadId}");
            return result;
        }
        #endregion
复制代码

 

posted @   安静点--  阅读(178)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示