zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Python
    Kubernetes之二workload资源编排
    Kubernetes之一安装
    DockerFile
    Docker的安装和使用
    Elastic Stack配置和使用
    虚拟化KVM应用
    Tomcat安装和使用
    Keepalived实现双主模型的ipvs高可用集群+实现双主模型的nginx高可用集群
    实验lvs+dns+nfs+mysql+web
  • 原文地址:https://www.cnblogs.com/anjingdian/p/15309436.html
Copyright © 2011-2022 走看看