asp.net-mvc-4 - 使用await/async时执行的代码是什么?

标签 asp.net-mvc-4 async-await

这里是来自 https://www.asp.net/mvc/overview/performance/using-asynchronous-methods-in-aspnet-mvc-4 的示例代码

public async Task<ActionResult> GizmosAsync()
{
    ViewBag.SyncOrAsync = "Asynchronous";
    var gizmoService = new GizmoService();
    return View("Gizmos", await gizmoService.GetGizmosAsync());
}

据我了解,async/await 对于释放工作线程非常有用,以便它可以处理其他请求。但 GetGizmosAsync 不仅是对“HttpResponse.Content.ReadAsAsync”的调用(我猜它是由 IO 池中的线程执行的),它还调用其他非异步代码,例如“var uri = Util.getServiceUri("Gizmos"); ”。

什么正在执行“var uri = Util.getServiceUri("Gizmos");”如果它不是来自工作池的线程?这里没有 IO。

最佳答案

您对异步的理解有点偏差。它允许线程返回到池如果它处于等待状态。最后一点很重要。该线程仍在执行代码,只是某些外部进程正在进行,目前不需要该线程,即网络通信、文件 I/O 等。一旦该外部进程完成,操作系统将负责恢复控制权交给原始进程,然后需要从池中请求新线程才能继续。

此外,仅仅因为代码的某些部分是异步的,并不意味着所有事情都是异步发生的:即只有其他代码是异步的并且实际上有资格成为异步的。正如我上面所说,线程只有在处于等待状态时才会被释放;运行同步意味着它没有等待,因此不会被释放。此外,有些事情永远不会是异步的,即使您尝试异步运行它们。任何 CPU 密集型操作都需要线程运行,因此线程永远不会进入等待状态,也永远不会被释放。

更新

假设似乎有其他一些线程实际上正在处理异步工作,但事实并非如此。正如我在评论中所说,操作系统级别的工作非常技术性,但是this is the best simplified explanation I've found 。文章的相关部分如下,供后代使用:

What About the Thread Doing the Asynchronous Work?

I get asked this question all the time. The implication is that there must be some thread somewhere that’s blocking on the I/O call to the external resource. So, asynchronous code frees up the request thread, but only at the expense of another thread elsewhere in the system, right? No, not at all.

To understand why asynchronous requests scale, I’ll trace a (simplified) example of an asynchronous I/O call. Let’s say a request needs to write to a file. The request thread calls the asynchronous write method. WriteAsync is implemented by the Base Class Library (BCL), and uses completion ports for its asynchronous I/O. So, the WriteAsync call is passed down to the OS as an asynchronous file write. The OS then communicates with the driver stack, passing along the data to write in an I/O request packet (IRP).

This is where things get interesting: If a device driver can’t handle an IRP immediately, it must handle it asynchronously. So, the driver tells the disk to start writing and returns a “pending” response to the OS. The OS passes that “pending” response to the BCL, and the BCL returns an incomplete task to the request-handling code. The request-handling code awaits the task, which returns an incomplete task from that method and so on. Finally, the request-handling code ends up returning an incomplete task to ASP.NET, and the request thread is freed to return to the thread pool.

Now, consider the current state of the system. There are various I/O structures that have been allocated (for example, the Task instances and the IRP), and they’re all in a pending/incomplete state. However, there’s no thread that is blocked waiting for that write operation to complete. Neither ASP.NET, nor the BCL, nor the OS, nor the device driver has a thread dedicated to the asynchronous work.

When the disk completes writing the data, it notifies its driver via an interrupt. The driver informs the OS that the IRP has completed, and the OS notifies the BCL via the completion port. A thread pool thread responds to that notification by completing the task that was returned from WriteAsync; this in turn resumes the asynchronous request code. There were a few threads “borrowed” for very short amounts of time during this completion-notification phase, but no thread was actually blocked while the write was in progress.

This example is drastically simplified, but it gets across the primary point: no thread is required for true asynchronous work. No CPU time is necessary to actually push the bytes out. There’s also a secondary lesson to learn. Think about the device driver world, how a device driver must either handle an IRP immediately or asynchronously. Synchronous handling is not an option. At the device driver level, all non-trivial I/O is asynchronous. Many developers have a mental model that treats the “natural API” for I/O operations as synchronous, with the asynchronous API as a layer built on the natural, synchronous API. However, that’s completely backward: in fact, the natural API is asynchronous; and it’s the synchronous APIs that are implemented using asynchronous I/O!

关于asp.net-mvc-4 - 使用await/async时执行的代码是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40486912/

相关文章:

c# - 如何在现有 Azure MVC ASP.NET Web 应用程序上启用 "host in the cloud"

c# - jQuery 数据表插件 : Get json from server and displaying table

c# - dotnetopenauth OAuth2AuthorizationServer 示例修改 ResourceServerEncryptionPublicKey

javascript - 在Typescript中使用异步方法链接(只是找到了解决方案)

ajax - 如何通过 ajax 操作向表添加行link

javascript - 如何将 Node.js 异步流回调转换为异步生成器?

c# - 异步 : What practices in large classes?

c# - 如何使用 Async/Await 进行进度报告

node.js - Nodejs - 这段代码的执行顺序是什么? for of 循环内的异步等待

html - Amazon s3 文件上传到存储桶成功后不重定向