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

use*_*000 15 .net c# asynchronous async-await

我试图完全理解async- await我理解中的一个缺点就是看到"一路走下去".我创建了一个async方法,它被另一个async方法等调用,一直到我理解的模糊术语,如"一个UI"或"一个可以处理多个请求的Web服务器".我如何用技术术语描述什么是"一直向下"?

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

[HttpGet]
public async Task<IHttpActionResult> GetRecords()
{
    var records = await repository.GetRecordsFromDbAsync();
    return Ok(records);
}
Run Code Online (Sandbox Code Playgroud)

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

Avn*_*tan 17

"异步一路下来"这句话是有点误导,因为它通常指的是一旦你使用异步方法,你需要有异步方法一路事实上向上(或向后,这取决于你的心理图像) -从您的异步方法到其调用方,然后是调用方的调用方,等等,一直回来.

您的示例显示了一个公开async任务的WebApi/MVC控制器.在接下来的步骤async链是接收HTTP GET请求,将其映射到控制器,并分派呼叫到控制器的方法的WebAPI/MVC基础设施.这个基础架构是async知道的,这意味着它知道async正确地调用控制器方法以及await它们返回HTTP响应的结果.

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

  • 我会说这句话的措辞是基于"它一直是乌龟",因为它支持类似的类比. (7认同)

MSa*_*ers 13

一路下来就是Win32 API.在该级别,异步I/O通过OVERLAPPED对象完成,并且可警告等待,例如WaitForMultipleObjectsEx.

  • @ user7127000这里有关于这个主题的好文章:http://blog.stephencleary.com/2013/11/there-is-no-thread.html (2认同)

Pat*_*man 6

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

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


Dar*_*erg 5

每种过程式编程语言都是一系列函数/过程调用,一个函数/过程调用另一个函数/过程。可以使用调用图来表示从过程到过程的调用序列,请参阅维基百科以获取调用图的起点。这些图通常显示从顶部开始到底部的过程调用序列。

我快速制作了 ASP .NET MVC 应用程序的部分调用图的图表。该图只是 ASP .NET MVC 应用程序的部分表示,因为它省略了操作系统(例如 Windows)、Web 服务器(例如 IIS)和 ASP .NET 的各种组件最初接收请求等内容负责在 HTTP 请求通过 ASP .NET 请求处理管道时对其进行处理。为了讨论的目的,这些问题可以被省略。尽管值得注意的是,它们将位于调用图的顶部,因为它们处理处理 HTTP 请求的初始阶段,并且最终在某个时刻 ASP .NET 最终调用控制器的操作。

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

与“一路向下”的概念一致的问题的答案是“我是一个异步方法”。这个异步方法有什么作用?嗯,这取决于你想做什么?如果您正在读取或写入文件,那么这是读取或写入文件的异步调用。您正在进行数据库查询吗?然后调用进行该查询的异步方法。考虑到这一点,我想您可以说,底层通常是设备驱动程序方法,它异步执行 IO 访问。尽管它很可能是您希望执行的长时间运行的计算密集型异步操作,例如处理图像或视频文件。

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


Cod*_*ray 5

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

\n

如果要异步完成某些操作,则在所有级别\xe2\x80\x94 上,它应该始终是异步的,因此,“一直向下”(向上)层次结构/调用堆栈/等。换句话说,在异步代码中的任何点进行同步、阻塞调用都是没有意义的,因为那样它根本就不是真正的异步。

\n

来自 .NET 并行编程团队的博客文章“我应该为异步方法公开同步包装器吗?”

\n
\n

一直异步

\n

这里的要点是,在将异步 API 包装为同步 API 时需要非常小心,如果你\xe2\x80\x99 不小心,你可能会遇到真正的问题。如果您发现自己认为需要从期望同步调用的\xe2\x80\x99 中调用异步方法(例如,您\xe2\x80\x99 正在实现一个具有同步方法的接口,但为了实现该接口(您需要使用仅异步公开的功能),首先确保它确实非常必要;虽然将 \xe2\x80\x9csync 包装在 async\xe2\x80\x9d 上似乎比重新调整这个或那个代码路径从上到下异步更方便,但从长远来看,重构通常是更好的选择如果可能的话,解决方案。

\n
\n

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

\n