我正在为我们的新后端项目考虑一些框架/编程方法。它关注BackendForFrontend实现,它聚合下游服务。为简单起见,这些是它通过的步骤:
事件驱动编程如何比常规"更好?每个请求处理线程?一些网站试图解释,它经常归结为这样的事情:
第二种解决方案是非阻塞呼叫。调用者不再等待答案,而是继续执行,但提供了一旦数据到达就会执行的回调。
我不明白:我们需要一个线程/处理程序来等待这些数据,对吧?它很好,事件处理程序可以继续,但我们仍然需要(在这个例子中)每个请求等待每个下游请求的线程/处理程序,对吗?
考虑这个例子:下游请求需要n秒才能返回。在这n秒内,r请求进来。在每个请求的线程中,我们需要r个线程:每个请求一个。经过n秒后,第一个线程完成处理并可用于新请求。
在实现事件驱动设计时,我们需要r + 1个线程:事件循环和r个处理程序。每个处理程序接收一个请求,执行它,并在完成后调用回调。
那么这怎么改善了呢?
答案 0 :(得分:2)
我不明白:我们需要一个线程/处理程序来等待这些数据, 正确?
不是真的。 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等有趣的项目。而且我很确定其他语言还有很多其他语言。
答案 1 :(得分:0)