为什么阻塞线程比 async/await 消耗更多?

Dir*_*oer 3 .net c# multithreading asynchronous async-await

看到这个问题和答案;

当 IIS 已经处理请求并发时,为什么要使用异步控制器?

好的,一个线程比 async/await 结构消耗更多的资源,但为什么呢?核心区别是什么?您仍然需要记住所有状态等,不是吗?

为什么一个线程池会受到限制,但是你能有更多空闲的 async/await 结构吗?

是因为 async/await 更了解您的应用程序吗?

Sha*_*rtz 5

好吧,让我们想象一个网络服务器。大多数时候,他所做的就是等待。它通常并不真正受 CPU 限制,但更多受 I/O 限制。它等待网络 I/O、磁盘 I/O 等。每次他等待之后,他都有一些事情(通常很短的事情要做),然后他所做的就是再次等待。现在,有趣的部分是他等待时发生的事情。在最“微不足道”的情况下(当然这绝对不是生产),您将创建一个线程来处理您拥有的每个套接字。

现在,每个线程都有自己的成本。一些句柄,1MB 的堆栈空间……当然,并不是所有这些线程都可以同时运行——所以操作系统调度程序需要处理这个问题,并每次都选择正确的线程来运行(这意味着很多上下文交换)。它将适用于 1 个客户。它适用于 10 个客户。但是,让我们想象一下同时有 10,000 个客户。10,000 个线程意味着 10GB 的内存。这比世界上的平均网络服务器还要多。

所有这些资源,都是因为你为一个用户专用了一个线程。但是,这些线程中的大多数什么都不做!他们只是等待某事发生。并且操作系统具有用于异步 IO 的 API,它允许您将一个操作排队,该操作将在 IO 操作完成后完成,而无需专用线程等待它。

如果您使用 async/await,您可以编写使用更少线程的应用程序,并且每个线程将被更多地利用 - 更少的“无所事事”时间。

async/await 不是唯一的方法。您可以在引入 async/await 之前完成此操作。但是,async/await 允许您编写非常易读且易于编写的代码,并且看起来几乎就像它只在单个线程上运行一样(不像以前那样移动很多回调和委托)。

通过结合 async/await 的简单语法和操作系统的一些特性,如异步 I/O(通过使用 IO 完成端口),您可以编写更具可扩展性的代码,而不会失去可读性。

另一个著名的示例是 WPF/WinForms。你有 UI 线程,他所做的只是处理事件,通常没有什么特别的事情要做。但是,您不能阻止它,否则 GUI 将挂起并且用户不会喜欢它。通过使用 async/await 并将每个“艰巨”的工作拆分为简短的操作,您可以实现负责任的 UI 和可读的代码。如果您必须访问数据库来执行查询,您将从 UI 线程开始异步操作,然后您将“等待”它,直到它结束并且您有可以在 UI 线程中处理的结果(因为例如,您需要将它们显示给用户)。您以前可以这样做,但使用 async/await 使其更具可读性。

希望能帮助到你。