在.NET面试中,多线程是必考题,尤其是现在的async/await语法糖。首先面试官会问到async/await的原理,async/await使用的优点,以及它们的使用场景。结果小白这次面试官问了原理后居然没有问其它两个问题,而问了"async方法体中有多个await方法调用,方法中await方法调用顺序?",尽管小白听了很多这块的讲解,这么简单的问题这次居然未正确回答,现在他想想都生气。本文讨论这个问题。
解析
这个问题答案很简单,async方法体中有多个await方法调用,方法中await方法调用是顺序调用。这个为啥呢?我们使用案例来说明,代码如下:
async Task Test()
{
await task1();
await task2();
}
async Task task1()
{
Thread.Sleep(10000);//为了体现是否按顺序执行,这个设定10秒
Console.WriteLine("测试1:关注dotnet开发跳槽");
}
async Task task2()
{
Thread.Sleep(500);//这个设定0.5秒
Console.WriteLine("测试2:关注dotnet开发跳槽");
}
以上方法用了sleep等待,如果不是顺序执行那么会先task2,但是这里执行的是task1,说明了是按照顺序执行的。如下图:
为啥呢?当在 async 方法体中使用多个 await 操作时,每个 await 操作都将在它出现的位置等待,直到它的对应的异步操作完成。所以,在上述示例中,task1 和 task2 按照顺序完成,并且在完成后执行其余的代码。
接下来我们回顾一下其它几个问题
1、async/await的原理?
async/await 是 C# 中用于异步编程的关键字。它们允许你在异步方法中使用同步风格的代码,而无需显式地使用回调或使用 Task 对象。
这是通过在方法上使用 async 关键字并使用 await 关键字来挂起方法的执行来实现的。当方法被挂起时,它会保留当前的执行上下文,然后在异步操作完成后恢复执行。
async/await 关键字的底层运行原理是基于 .NET 的异步模式实现的。当你使用 await 关键字等待一个异步操作时,实际上是在调用该操作的 GetAwaiter 方法。
这个方法会返回一个对象,该对象实现了 INotifyCompletion 接口。当异步操作完成时,这个对象会调用它的 OnCompleted 方法。
当你使用 await 关键字时,编译器会生成一些额外的代码来调用 GetAwaiter 方法并检查异步操作的完成状态。如果操作已经完成,它会立即返回结果。如果操作尚未完成,它会注册一个回调函数,在操作完成时调用该函数。
这样,当你使用 await 关键字时,代码执行就会被挂起,直到异步操作完成。这样,你就可以在异步方法中编写同步风格的代码,而无需手动编写回调函数或使用其他复杂的异步模式。
总而言之,async/await 关键字是通过使用 .NET 异步模式来简化异步编程的。它们允许你在异步方法中编写同步风格的代码,并且可以让你的代码更加简单、可读和可维护。
2、使用async/await的优点
简化异步编程:async/await 关键字允许你在异步方法中使用同步风格的代码,而无需显式地使用回调函数或处理 Task 对象。这样可以让你的代码更加简单易懂。
提高代码可读性:async/await 关键字可以让你的代码更加流畅,更容易理解。因为它们允许你在异步方法中编写同步风格的代码,所以你的代码看起来就像是同步代码,而不是嵌套的回调函数。
增强错误处理能力:使用 async/await 关键字可以让你使用 try/catch 语句来处理异步操作中的异常。这样可以让你的代码更加结构化,并且更容易处理错误情况。
提升程序性能:使用 async/await 关键字可以让你的程序在等待异步操作完成时进入休眠状态,从而允许其他代码在此期间运行。这样可以让你的程序更有效地利用 CPU 资源,并提升性能。
3、async/await使用场景
async/await 关键字通常用于执行异步 I/O 操作,例如从网络或磁盘读取数据。这种情况下,使用 async/await 关键字可以让你在等待操作完成时挂起线程,从而节省了 CPU 资源。