教程有时指向自己的异步方法的实现,例如这段代码:
async public static Task GetHttpResponseAsync()
{
using (HttpClient httpClient = new HttpClient())
{
HttpResponseMessage response = await httpClient.GetAsync(...);
Console.WriteLine(response.Something);
}
}
我清楚的是异步工作通常如何,但没有一个教程解释内部如何实现
httpClient.GetAsync(...);
了解asynchoronus代码如何在细节中工作非常重要。令我好奇的是,如果GetAsync的内部操作(那些方法或其他异步方法)是在执行此代码的某种容器中注册的?操作系统是否必须支持异步方法(例如,它使用的是windows api)?如果我想实现我自己的异步文件下载器(从磁盘而不是.NET框架的必要部分),我将如何实现它,我应该在某处注册我的方法以进一步调用?
我很清楚,在内部,编译器生成状态机,在DoSomething()方法执行它所需的操作之后,它只是再次调用此状态机以在等待之后恢复执行代码。
另外我不清楚的是异步代码如何在同一个线程上运行。我认为维护状态机必须在同一个线程上,但httpClient.GetAsync()的代码如何在同一个线程上运行,并且不会中断其他操作(f.e gui)。必须有一些东西使这个代码在单独的线程上运行(在所有情况下)。我错了吗?我错过了什么?
对我的问题的补充说明:在JavaScript中,据我所知和理解,异步方法的工作原理是将它们注册到某种容器(在不同的线程上逐个运行它们)来执行此方法。在完成方法执行后,结果将返回给用户上下文,对我来说很清楚,这是否在这里工作?
答案 0 :(得分:2)
简而言之,必须在操作系统级别提供真正的异步。正如您所指出的,async
/ await
是一种语言级功能,它使用编译器生成的状态机来解析"分解"您的方法可以异步运行,但它依赖于操作系统原语(中断,线程)以异步方式实际执行此工作。
但是,重要的是要注意,不通常是为处理异步操作而创建的线程。我将按照这篇专业撰写的文章来描述为什么会这样:http://blog.stephencleary.com/2013/11/there-is-no-thread.html
在Windows上,执行异步工作的主要机制是I/O Completion Ports。这是一个Windows API,由许多.NET类型引用,包括您正在使用的HttpClient
。
请注意,对于非I / O操作,您也可以始终使用Threads,或者更好地使用Thread Pool API来执行将异步完成的后台工作。
Windows API中的ReadFile(或更新ReadFileEx)函数旨在与异步I / O一起使用。当您调用ReadFile
时,您可以使用FILE_FLAG_OVERLAPPED
标志并将OVERLAPPED
结构传递给lpOverlapped
参数,从而启用异步读取。我建议您使用此API来设计文件下载程序。
总结:
HttpMessageHandler.cs
- > HttpClientHandler.Windows.cs
- > WinHttpHandler.cs
- > Interop.winhttp.cs
- > PInvoke到WinHTTP API本机DLL - >带有I / O完成端口的Winsock套接字。