R. *_*man 4 webserver multithreading event-driven-design event-driven
我正在为我们的新后端项目考虑一些框架/编程方法。它涉及一个 BackendForFrontend 实现,它聚合下游服务。为简单起见,这些是它经过的步骤:
事件驱动编程如何比“常规”线程每请求处理更好?一些网站试图解释,通常归结为这样的:
第二种解决方案是非阻塞调用。调用者没有等待答案,而是继续执行,但提供了一个回调,一旦数据到达就会执行。
我不明白的是:我们需要一个线程/处理程序来等待这些数据,对吗?很高兴事件处理程序可以继续,但我们仍然需要(在本例中)每个请求的线程/处理程序等待每个下游请求,对吗?
考虑这个例子:下游请求需要 n 秒才能返回。在这 n 秒内,r 个请求进来。在 thread-per-request 中,我们需要 r 个线程:每个请求一个。经过 n 秒后,第一个线程完成处理并可用于新请求。
在实现事件驱动设计时,我们需要 r+1 个线程:一个事件循环和 r 个处理程序。每个处理程序接受一个请求,执行它,并在完成后调用回调。
那么这如何改进呢?
我不明白的是:我们需要一个线程/处理程序来等待这些数据,对吗?
并不真地。NIO 背后的想法是没有线程被阻塞。
这很有趣,因为操作系统已经以非阻塞方式工作。我们的编程语言是以阻塞方式建模的。
例如,假设您有一台只有一个 CPU 的计算机。您执行的任何 I/O 操作都将比 CPU 慢几个数量级,对吗?假设你想读取一个文件。你认为 CPU 会呆在那里,空闲,什么都不做,而磁盘头去取几个字节并将它们放在磁盘缓冲区中吗?显然不是。操作系统将注册一个中断(即回调),同时将宝贵的 CPU 用于其他用途。当磁头成功读取几个字节并使其可供使用时,将触发中断,然后操作系统会关注它,恢复先前的进程块并分配一些 CPU 时间来处理可用数据。
因此,在这种情况下,CPU 就像应用程序中的一个线程。它永远不会被阻止。它总是在做一些受 CPU 限制的事情。
NIO 编程背后的想法是相同的。在您公开的情况下,假设您的 HTTP 服务器有一个线程。当您收到来自客户端的请求时,您需要发出一个上游请求(代表 I/O)。因此,NIO 框架在这里要做的是发出请求并在响应可用时注册回调。
紧接着,您宝贵的单线程被释放以处理另一个请求,该请求将注册另一个回调,依此类推。
当回调解决时,它将自动安排由您的单线程处理。
因此,该线程用作事件循环,您应该在其中只安排 CPU 绑定的内容。每次需要进行 I/O 时,都是以非阻塞方式完成的,当 I/O 完成时,一些 CPU 绑定的回调会被放入事件循环中以处理响应。
这是一个强大的概念,因为使用非常少量的线程,您可以处理数千个请求,因此您可以更轻松地扩展。事半功倍。
这个特性是Node.js的主要卖点之一,也是为什么即使使用单线程也可以用来开发后端应用程序的原因。
同样,这也是Netty、RxJava、Reactive Streams Initiative和Project Reactor等框架激增的原因。他们都在寻求推广这种类型的优化和编程模型。
还有一个有趣的新框架运动,它们利用了这一强大的功能,并试图相互竞争或互补。我说的是像Vert.x和Ratpack这样有趣的项目。而且我很确定还有更多其他语言可供使用。
| 归档时间: |
|
| 查看次数: |
655 次 |
| 最近记录: |