没有UI线程的专用后端服务器上的异步代码是否有优势?

发布于 2025-01-22 20:04:16 字数 337 浏览 2 评论 0原文

我有一个开发人员挑战前几天使用异步服务器端代码的使用。他问为什么异步代码优于没有UI线程的服务器上的同步代码?我给了他典型的线耗尽答案,但是在考虑了一段时间之后,我不再确定我的答案是正确的。进行了一些研究之后,我发现操作系统中线的上限受内存而不是任意数字的控制。和诸如Kestrel支持无限线程的服务器。因此,在“理论”中,服务器可以并行阻止的请求数(线程)受内存约束。这与.net中的异步代码没有什么不同;它将堆栈变量提升到堆,但仍然是内存绑定的。

我一直以为比我更聪明的人通过这一想法,而异步代码是处理IO绑定代码的正确方法。但是,在没有UI线程的专用服务器农场运行时,Async .NET代码的可测量是什么?转向云(AWS)是否会改变答案?

I had a developer challenge the use of asynchronous server side code the other day. He asked why asynchronous code is superior to synchronous code on a server with no UI thread to block? I gave him the typical thread exhaustion answer but after thinking about it for a while I was no longer sure my answer was correct. After doing a little research I found that the upper limit to threads in an OS is governed by memory not an arbitrary number. And servers like Kestrel support unlimited threads. So in "theory" the number of requests (threads) a server can block on in parallel is governed by memory. Which is no different than async code in .NET; it lifts stack variables to the heap but it's still memory bound.

I've always assumed that smarter people than me had thought this through and async code was the right way to handle IO bound code. But what are the measurable advantages of async .NET code when running in a dedicated server farm with no UI thread? Does a move to the cloud (AWS) change the answer?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

|煩躁 2025-01-29 20:04:17

服务器端异步代码目的与异步UI代码完全不同。
异步UI代码使UI响应更快(尤其是在多个CPU内核时),它允许多个UI任务并行运行,从而改善UI用户体验。

另一方面,服务器端异步代码的目的是最大程度地减少为多个客户提供服务所需的资源。实际上,即使只有一个CPU核心或一个单线程事件循环,例如 node.js 。这一切都归结为一个简单的概念
asynchronous io io

同步和异步IO之间的区别在于,如果以前的线程,则暂停了IO操作的线程,直到完成IO操作(例如,直到执行DB请求或读取磁盘上的文件)。然后,一旦完成IO操作来处理结果,则相同的线程将不置。注意:即使暂停了线程,该线程很可能不使用任何CPU资源(可能是由线程调度程序入睡),但其资源仍然与此特定的IO操作有关,并且在硬件执行IO时几乎浪费了。有效地,使用同步IO,即使大多数线程可能正在睡觉等待其IO操作完成,您将至少每次处理一个线程。在.NET中,每个线程至少具有分配的堆栈至少1MB,因此,如果服务器当前正在处理1000个请求,则仅为线程堆栈分配了几乎1GB的内存,以及用于线程调度程序的额外负担,并且CPU花费更多的时间来进行上下文开关。 :线程越多,系统的总体性能越慢。分配的内存更多意味着效率较低的内存/CPU缓存使用情况。

异步IO更有效,因为一个工作线程只会初始化IO操作,而不是等待完成,而是立即切换到另一个有用的任务(例如,延续另一个客户端的请求处理),当硬件完成IO操作时在任何可用的工作线程上恢复结果的处理。结果,取决于等待硬件完成IO的整体时间与完成CPU任务所花费的时间(例如,IO操作的结果序列化到JSON中的时间),此方法可以使用更少的线程为了服务相同数量的同时客户端请求:如果在IO中花费90%的时间,我们可以仅使用100个线程来服务相同的1000个同时请求。您的服务器端代码越多的是与CPU结合的范围与CPU结合,越同时的客户端请求使用给定数量的资源可以处理:CPU和内存。

异步代码的缺点是什么?通常,它比同步更难编写。异步代码使用回调来恢复操作,因此,编程器需要将代表(延续)传递给IO方法,而不是简单的线性代码,该方法后来在IO操作完成时由系统调用(可能在其他线程上)。然而,现代的C#带有其async/等待设施使此任务变得不复杂,甚至使异步代码几乎看起来像同步。唯一要记住的事情是:异步代码仅在异步“一直以下”时起作用:即使是单个 task.wait task.result 在初始http请求处理到db请求呼叫的呼叫堆中的某个地方使整个代码使整个代码同步,从而迫使当前的工作线程等待等待等待致电以完成击败目的。注意:<代码>等待在C#代码中实际上并未等待调用结果,而是由编译器转换为继续与 ie继续进行连续回调,尽管实际上有点比这更复杂,但幸运的是,复杂性是从程序员中隐藏的,所以如今编写有效的异步代码是相对简单的任务。

Server-side asynchronous code purpose is completely different from asynchronous UI code.
Asynchronous UI code makes UI more responsive (especially when multiple CPU cores are available), it allows multiple UI tasks to run in parallel which improves UI user experience.
The purpose of server-side asynchronous code on the other hand is to minimise the resources necessary to serve multiple clients simultaneously. In fact it is beneficial even if there is only one CPU core or a single-threaded event loop like in Node.js. And it all boils down to a simple concept of
Asynchronous IO.

The difference between synchronous and asynchronous IO is that in case of the former the thread which initialises an IO operation is paused until the IO operation is completed (e.g. until DB request is executed or a file on a disk is read). The same thread is then un-paused once the IO operation is completed to process the result of it. Note: even though while paused the thread is most likely not using any CPU resources (it is probably put to sleep by a thread scheduler) its resources are still tied to this particular IO operation and are pretty much wasted while IO is executed by the hardware. Effectively with synchronous IO you will need at least one thread per currently being processed client request even though most of those threads are probably asleep waiting for their IO operations to complete. In .NET each thread has at least 1MB of stack allocated so if the server is currently processing say 1000 requests it leads to almost 1GB of memory allocated simply for thread stacks plus an additional burden for a thread scheduler and more time CPU spends doing context switches: the more threads there are the slower overall performance of the system. More memory allocated means less efficient memory/CPU caches usage too.

Asynchronous IO is more efficient because a worker thread only initialises an IO operation and instead of waiting for it to complete it is immediately switched to another useful task (e.g. continuation of another client's request processing) and when the IO operation is completed by the hardware the processing of the result is resumed on any available worker thread. As a result, depending on the ratio between overall time spent waiting for hardware to complete IO and the time spent doing CPU tasks (e.g. serialisation of the result of IO operation into JSON) this approach can use less threads to serve the same number of simultaneous client requests: if, say, 90% of the time is spent in IO we can potentially use only 100 thread to serve the same 1000 simultaneous requests. The more your server-side code is IO-bound vs CPU-bound the more simultaneous clients requests it can process using a given amount of resources: CPU and memory.

What is the drawback of asynchronous code? Mainly it is generally harder to write than synchronous. Asynchronous code uses callbacks to resume operation so instead of a simple linear code a programmer needs to pass a delegate (a continuation) to IO method which is later called by the system when IO operation is completed (potentially on a different thread). However modern C# with its async/await facilities makes this task less complicated and even makes asynchronous code to almost look like synchronous. The only thing to remember: the asynchronous code only works when it is asynchronous "all the way down": even a single Task.Wait or Task.Result somewhere in the stack of calls from initial HTTP request processing to DB request call makes entire code synchronous thus forcing the current working thread to wait for that Wait call to finish defeating the purpose. Note: await in C# code does not actually awaits to the result of the call but is converted by the compiler to a ContinueWith i.e. to a continuation callback though in practice it is a bit more complicated than that but luckily the complexity is hidden from a programmer so nowadays writing efficient asynchronous code is relatively straightforward task.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文