• .net 中的async,await理解


    理解:

    1、async修饰的方法可理解为异步方法(必须要配合await,否则和普通方法无异)
    2、当async方法执行遇到await,则立即将控制权转移到async方法的调用者
    3、由调用者决定是否需要等待async方法执行完再继续往下执行
    4、await会挂起当前方法,即阻塞当前方法继续往下执行,转交控制权给调用者

    注意:如果调用一个async方 法,却不使用await关键字来标记一个挂起点的话,程序将会忽略async关键字并以同步的方式执行。编译器会对类似的问题发出警告。

    例子一:(控制台程序)

     1         static void Main(string[] args)
     2         {
     3             MyMain();//由于main方法无法定义成async,顾此定义一个方法MyMain来表示main方法。
     4             Console.Read();
     5         }
     6         static async void MyMain()
     7         {
     8             Console.WriteLine("main方法开始执行");
     9             AsyncAction();
    10             Console.WriteLine("main方法继续执行");
    11             Console.WriteLine("main方法执行结束");
    12         }
    13 
    14         static async Task<string> AsyncAction()
    15         {
    16             Console.WriteLine("AsyncAction方法await之前");
    17             string result = await Task<string>.Run(() =>
    18             {
    19                 Thread.Sleep(1000);
    20                 Console.WriteLine("AsyncAction方法sleep一秒后");
    21                 return "AsyncAction的返回值";
    22             });
    23             Console.WriteLine("AsyncAction方法await之后-{0}", result);
    24             return result;
    25         }

    执行结果:

    由返回结果可以知,此异步方法AsyncAction执行遇到await,即程序执行到此行立刻被挂起,将控制权限交给MyMain方法,由MyMain决定是否等待AsyncAction执行完再往下执行,此处由于执行AsyncAction方法前不加await,所以直接往下执行。而AsyncAction方法中的await Task.Run(包括)后的代码会异步执行。

    例子二:例子一中MyMain方法执行AsyncAction前面加await

     1         static void Main(string[] args)
     2         {
     3             MyMain();//由于main方法无法定义成async,顾此定义一个方法MyMain来表示main方法。
     4             Console.Read();
     5         }
     6         static async void MyMain()
     7         {
     8             Console.WriteLine("main方法开始执行");
     9             await AsyncAction();
    10             Console.WriteLine("main方法继续执行");
    11             Console.WriteLine("main方法执行结束");
    12         }
    13 
    14         static async Task<string> AsyncAction()
    15         {
    16             Console.WriteLine("AsyncAction方法await之前");
    17             string result = await Task<string>.Run(() =>
    18             {
    19                 Thread.Sleep(1000);
    20                 Console.WriteLine("AsyncAction方法sleep一秒后");
    21                 return "AsyncAction的返回值";
    22             });
    23             Console.WriteLine("AsyncAction方法await之后-{0}", result);
    24             return result;
    25         }

    执行结果:

    由于AsyncAction方法执行前加了await,故MyMain方法要等待其执行结束才继续往下执行。

    使用场景及用法分析:

    当有某一操作执行时间较长或者执行结果对整体程序执行影响不大(一般此操作都会是一个独立一个方法。)主线程的执行不依赖于此操作的执行结果。
    常见于一些IO操作,如日志的记录,当触发记录日志动作的时候,应该让其独立一个线程去执行,此时不管日志记录成功与否,
    都不应该阻塞主线程的执行。
    在上面的例子一中,可以将AsyncAction方法中的 Task.Run 当成记录日志的动作,当程序执行到 await Task.Run后,
    AsyncAction方法立刻被挂起,主线程MyMain继续往下执行。
    这里可能有人会疑问?为何不直接在主线程MyMain中直接开启线程 Task.Run 来记录日志?
    而是要定义到一个异步方法(此例子为AsyncAction方法)中处理日志。
    是,如果此时只是为了记录日志,也不是必须要写到一个方法中。但是,
    首先,这种单一功能的操作,本应该就是独立写到一个方法中。
    其次是 AsyncAction方法 中的 await Task.Run 的返回值也许还有其他操作。

    如下面例子:记录日志之前,需要获取登陆用户的一些信息,并且将用户信息一同保存到日志中,如果写到主线程MyMain中,则避免不了阻塞主线程(因为需要等待获取用户信息)。
    当然,你也可以将这两个方法一起写到一个方法中由Task调用,这里只是举个例子来说明Async和await的用法场景。

     1         static void Main(string[] args)
     2         {
     3             MyMain();//由于main方法无法定义成async,顾此定义一个方法MyMain来表示main方法。
     4             Console.Read();
     5         }
     6         static async void MyMain()
     7         {
     8             Console.WriteLine("main方法开始执行");
     9             WriteUserLog();
    10             Console.WriteLine("main方法继续执行");
    11             Console.WriteLine("main方法执行结束");
    12         }
    13 
    14         static async void WriteUserLog()
    15         {
    16             Console.WriteLine("获取用户信息之前");
    17             string userInfo = await GetUserInfoAsync(); //尽量早的使用await,以便此方法尽快挂起(异步执行)
    18             Console.WriteLine("写入日志之前");
    19             WriteLog(userInfo);
    20         }
    21 
    22         static Task<string> GetUserInfoAsync()
    23         {
    24             return Task.Factory.StartNew(() => {
    25                 Thread.Sleep(1000);
    26                 Console.WriteLine("获取用户信息完成");
    27                 return "jxf";
    28             });
    29         }
    30 
    31         static void WriteLog(string userInfo)
    32         {
    33             Thread.Sleep(1000);
    34             Console.WriteLine("写入日志完成,用户信息:{0}", userInfo);
    35         }

    执行结果:

  • 相关阅读:
    Makefile的介绍与使用(一)
    关于OpenWRT第一次编译时出现的一些问题
    ssh连接时出现 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! 解决办法
    ArcGIS 添加存WKT字符串的字段
    已连接的 RDBMS 实例未针对 Esri 空间类型配置进行相应设置
    ArcGIS10.2 安装好后,数据库连接的配置
    用Excel将中文转成大驼峰拼音
    将 Python 项目的所有py文件编译成.pyc
    地图要素增删改服务WFS: Openlayer+GeoServer+GeoPackage
    ArcGIS 和 QGIS 经常崩溃闪退的原因
  • 原文地址:https://www.cnblogs.com/fnz0/p/10691594.html
Copyright © 2020-2023  润新知