.net 中的async,await理解

江枫思渺然 提交于 2020-01-02 04:47:45

理解:

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         }

执行结果:

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!