.net 中的async,await理解

时间:2023-03-09 01:40:53
.net 中的async,await理解

理解:

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

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

例子一:(控制台程序)

         static void Main(string[] args)
{
MyMain();//由于main方法无法定义成async,顾此定义一个方法MyMain来表示main方法。
Console.Read();
}
static async void MyMain()
{
Console.WriteLine("main方法开始执行");
AsyncAction();
Console.WriteLine("main方法继续执行");
Console.WriteLine("main方法执行结束");
} static async Task<string> AsyncAction()
{
Console.WriteLine("AsyncAction方法await之前");
string result = await Task<string>.Run(() =>
{
Thread.Sleep();
Console.WriteLine("AsyncAction方法sleep一秒后");
return "AsyncAction的返回值";
});
Console.WriteLine("AsyncAction方法await之后-{0}", result);
return result;
}

执行结果:.net 中的async,await理解

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

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

         static void Main(string[] args)
{
MyMain();//由于main方法无法定义成async,顾此定义一个方法MyMain来表示main方法。
Console.Read();
}
static async void MyMain()
{
Console.WriteLine("main方法开始执行");
await AsyncAction();
Console.WriteLine("main方法继续执行");
Console.WriteLine("main方法执行结束");
} static async Task<string> AsyncAction()
{
Console.WriteLine("AsyncAction方法await之前");
string result = await Task<string>.Run(() =>
{
Thread.Sleep();
Console.WriteLine("AsyncAction方法sleep一秒后");
return "AsyncAction的返回值";
});
Console.WriteLine("AsyncAction方法await之后-{0}", result);
return result;
}

执行结果:.net 中的async,await理解

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

使用场景及用法分析:

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

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

         static void Main(string[] args)
{
MyMain();//由于main方法无法定义成async,顾此定义一个方法MyMain来表示main方法。
Console.Read();
}
static async void MyMain()
{
Console.WriteLine("main方法开始执行");
WriteUserLog();
Console.WriteLine("main方法继续执行");
Console.WriteLine("main方法执行结束");
} static async void WriteUserLog()
{
Console.WriteLine("获取用户信息之前");
string userInfo = await GetUserInfoAsync(); //尽量早的使用await,以便此方法尽快挂起(异步执行)
Console.WriteLine("写入日志之前");
WriteLog(userInfo);
} static Task<string> GetUserInfoAsync()
{
return Task.Factory.StartNew(() => {
Thread.Sleep();
Console.WriteLine("获取用户信息完成");
return "jxf";
});
} static void WriteLog(string userInfo)
{
Thread.Sleep();
Console.WriteLine("写入日志完成,用户信息:{0}", userInfo);
}

执行结果:.net 中的async,await理解