“异步一路走下去”:嗯,底部到底是什么?

我正在努力完全理解asyncawait ,我的理解中的一个async是看到什么是“一直向下”。 我创建了一个async方法,它被另一个async方法等调用,一直到我理解的模糊术语,如“一个UI”或“一个可以处理多个请求的Web服务器”。 我如何用技术术语描述什么是“一直向下”?

让我们来看一个Web服务器的第二个例子。 假设我有一个控制器动作

 [HttpGet] public async Task GetRecords() { var records = await repository.GetRecordsFromDbAsync(); return Ok(records); } 

我在哪里可以找到.NET源代码中的“一路向下”代码,它可以异步调用它?

每个过程编程语言都是一系列函数/过程调用,其中一个函数/过程调用另一个函数/过程。 可以使用调用图表示从过程到过程的这个调用序列, 参见维基百科,以获得调用图的起始点 。 这些图表通常显示从顶部开始并继续到底部的程序调用序列。

我快速生成了ASP .NET MVC应用程序的部分调用图表。 该图仅是ASP .NET MVC应用程序的部分表示,因为它省略了诸如操作系统(例如Windows),Web服务器(例如IIS)和ASP .NET的各种组件的初始接收请求之类的内容。它负责处理HTTP请求,因为它通过ASP .NET请求处理管道。 出于本讨论的目的,可以省略这些事项。 虽然值得注意的是它们会位于调用图的顶部,因为它们处理处理HTTP请求的初始阶段,并且最终,在某些时候ASP .NET最终会调用控制器的操作。

正如您在图中看到的,我已经表示了将由ASP .NET作为异步操作调用的控制器的操作。 在调用图的左侧是一系列异步过程调用。 最终它会到达你问题主题的方框。

与“一直向下”这个概念一致的问题的答案是“我是一个异步方法”。 这种异步方法有什么作用? 那么,这取决于你想做什么? 如果您正在读取或写入文件,那么它是一个异步调用来读取或写入文件。 你在做数据库查询吗? 然后调用是一个执行该查询的异步方法。 考虑到这一点,我猜你可以说通常底部的是一个设备驱动程序方法,它异步执行IO访问。 虽然它很容易成为您希望执行的长时间运行的计算绑定异步操作,例如处理图像或video文件。

值得注意的是调用图的右侧也是如此。 尽管通常您可能希望一直调用异步方法,但此调用图的右侧分支显示您根本不需要在底部调用异步方法。 在此处输入图像描述

短语“async all down down”有点误导,因为它通常指的是一旦你使用异步方法,你需要一直有异步方法(或者返回 ,取决于你的心理图像) -从您的异步方法到其调用方 ,然后是调用方的调用方,依此类推,一直回来。

您的示例显示了一个公开async任务的WebApi / MVC控制器。 async链中的下一步是WebApi / MVC基础结构,它接收HTTP GET请求,将其映射到控制器,并将调用分派给控制器的方法。 此基础结构是async感知的,这意味着它知道正确调用async控制器方法并await其结果返回HTTP响应。

至于如何实现该基础架构,我不是特别了解,也不关心 – 我知道ASP.NET Web服务支持async Task控制器,这对我来说已经足够了。

一直以来都是Win32 API。 在该级别,异步I / O通过OVERLAPPED对象和可警告等待(例如WaitForMultipleObjectsEx

GetRecordsFromDbAsync是一种异步方法,因此您的顶级异步方法(由支持异步的ASP.NET Web服务器调用)只是将其异步性移交给下一级别。

一直到GetRecordsFromDbAsync或其后代实际调用调用堆栈中的最后一个异步方法。 在那里它可能会变成本机,并且它会注册I / O中断或在读取文件时调用的其他内容,处理Web请求等。

从您的问题中不清楚您在哪里找到引用,或者在什么情况下使用它。 但是,“异步一直向下”通常被理解为意味着您不应在单个逻辑操作中在同步和异步方法之间来回切换。

如果要异步完成某些事情,它应该在所有级别上始终异步 – 因此,“一直向下”(和向上)层次结构/调用堆栈/等。 换句话说,在异步代码中的任何一点执行同步阻塞调用都没有意义,因为它根本不是异步的。

从.NET Parallel Programming团队的博客文章“我应该为异步方法公开同步包装器吗?” :

异步一直向下

这里的要点是,在将异步API包装为同步API时需要非常小心,好像你不小心,你可能遇到真正的问题。 如果您发现自己认为需要从期望同步调用的东西调用异步方法(例如,您正在实现一个具有同步方法的接口,但为了实现该接口,您需要使用仅有的function异步暴露),首先要确保它是真正的,真正必要的; 虽然将“同步异步”包装起来似乎更为便利,而不是重新检测这个或那个代码路径从上到下是异步的,但如果可能的话,重构通常是更好的长期解决方案。

至于你在.NET源代码中可以找到它的问题, MSalters已经回答了这个问题 。 从根本上说,.NET API将调用Windows操作系统提供的系统级API。 它们执行异步I / O,并在调用者完成后发出信号。 但是,您并不需要了解它在技术层面的工作原理; 这是抽象的全部要点。