操作系统必须支持异步方法或者是异步程序级功能

Puc*_*acz 5 c# asynchronous

教程有时会指向自己的异步方法的实现,例如以下代码:

async public static Task GetHttpResponseAsync()
{
   using (HttpClient httpClient = new HttpClient())
   {
       HttpResponseMessage response = await httpClient.GetAsync(...);
       Console.WriteLine(response.Something);
   }            
}
Run Code Online (Sandbox Code Playgroud)

我很清楚异步一般如何工作的,但没有一个教程解释内部是如何实现的

httpClient.GetAsync(...);
Run Code Online (Sandbox Code Playgroud)

这对于详细了解异步代码的工作原理非常重要。让我好奇的是 GetAsync 的内部操作(那些方法或其他异步方法)是否在执行此代码的某种容器中注册?操作系统是否必须支持异步方法(fe 它使用 windows api)?如果我想实现我自己的异步文件下载器(从磁盘并且没有来自 .NET 框架的重要部分),我将如何实现它,我应该在某处注册我的方法以供进一步调用吗?

对我来说很清楚,在内部,编译器制作状态机,在 DoSomething() 方法完成它必须做的事情之后,它只是再次调用这个状态机以在等待后继续执行代码。

另外我不清楚的是异步代码如何在同一线程上运行。我认为维护状态机必须在同一个线程上,但是 httpClient.GetAsync() 中的代码如何可以在同一个线程上运行并且不中断其他操作(fe gui)。必须有一些东西使此代码在单独的线程上运行(在所有情况下)。我错了吗?我错过了什么?

我的问题的附加解释:在 JavaScript 中,据我所知和理解,异步方法的工作原理是将它们注册到某种容器中(在单独的线程上一个一个地运行它们),该容器执行此方法。方法执行完成后,结果返回到用户上下文,我很清楚,这里的工作方式是否相同?

Rya*_*ann 5

简而言之,必须在操作系统级别提供真正的异步。正如您所指出的,async/await是一种语言级功能,它使用编译器生成的状态机将您的方法“分解”成可以异步运行的部分,但它依赖于操作系统原语(中断、线程)来实际执行这项工作异步方式。

但是,需要注意的是,通常不会创建线程来处理异步操作。我将遵循这篇专业撰写的文章来描述为什么会这样:http : //blog.stephencleary.com/2013/11/there-is-no-thread.html

在 Windows 上,执行异步工作的主要机制是使用I/O 完成端口。这是许多 .NET 类型(包括HttpClient您正在使用的)在幕后使用的 Windows API 。

请注意,对于非 I/O 操作,您也可以始终使用Threads或更好的Thread Pool API来执行将异步完成的后台工作。

Windows API 中的ReadFile(或更新的ReadFileEx)函数旨在与异步 I/O 一起使用。当您调用 时ReadFile,您可以使用该FILE_FLAG_OVERLAPPED标志并将一个OVERLAPPED结构传递给该lpOverlapped参数,从而启用异步读取。我鼓励你使用这个 API 来设计你的文件下载器。


总之:

  • 不会总是为异步操作创建线程。
  • async/await 是一种语言特性,但依赖于各种 Windows API 来实现真正的异步。
  • 如果您正在做的工作是 I/O 绑定,请考虑使用异步 I/O:https : //msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx
  • 如果您所做的工作受 CPU 限制,请考虑使用线程:https ://msdn.microsoft.com/en-us/library/windows/desktop/ms684841( v= vs.85) .aspx
  • 现在 .NET Core 在 GitHub 上是开源的,您实际上可以检查源代码以了解幕后发生的事情。这是HttpClient.cs,它使用HttpMessageHandler.cs-> HttpClientHandler.Windows.cs-> WinHttpHandler.cs-> Interop.winhttp.cs-> PInvoke 进入WinHTTP API本机 DLL -> 带有 I/O 完成端口的 Winsock 套接字。