当我探索 NodeJS 应用程序和 Java 应用程序如何处理请求时,我遇到了 Servlet 对请求的异步处理。
根据我在不同地方读到的内容:
请求将由 Servlet 容器中的 HTTP 线程接收和处理,如果发生阻塞操作(如 I/O),则可以将请求移交给另一个线程池,并且接收请求的 HTTP 线程可以返回接收请求并处理下一个请求。
耗时的阻塞操作现在将由线程池中的工作线程承担。
如果我的理解是正确的,我有以下问题:
如果我是对的,即使处理阻塞操作的线程也会等待该操作完成,从而阻塞资源(并且处理的线程数等于核心数)。
使用异步处理到底能带来什么好处?
如果没有,请赐教。
我可以用 Node.js 来解释它的好处(同样适用于其他地方)。
问题。阻塞网络 IO。
假设您要与服务器创建连接,以便从
连接,您将需要一个线程 T1,它将通过网络读取该连接的数据,
此读取方法是阻塞的,即您的线程将无限期地等待,直到有任何数据可供读取。现在假设此时您有另一个连接,现在要处理此连接,您必须创建另一个线程 T2。该线程很可能会再次被阻止读取第二个连接上的数据,因此这意味着您可以处理与系统中的线程一样多的连接。这称为“每个请求线程模型”。由于大量的上下文切换和调度,创建大量线程会降低系统性能。该模型的扩展性不好。
解决方案 :
一点背景知识,FreeBSD/Linux 中有一种称为 kqueue/epoll 的方法。这两种方法都接受 socketfd 列表(作为函数参数),调用线程会被阻塞,直到一个或多个套接字准备好读取数据,并且这些方法返回这些就绪连接的子列表。参考号http://austingwalters.com/io- Multiplexing/ http://austingwalters.com/io-multiplexing/
现在假设您对上述方法有了一定的了解。想象一下,有一个名为 EventLoop 的线程,它调用上述方法 epoll/kqueue。
所以在java中你的代码看起来像这样。
/*Called by Event Loop Thread*/
while(true) {
/**
* socketFD socket on which your server is listening
* returns connection which are ready
*/
List<Connection> readyConnections = epoll( socketFd );
/**
* Workers thread will read data from connection
* which would be very fast as data is already ready for read
* So they don't need to wait.
*/
submitToWorkerThreads(readyConnections);
/**
* callback methods are queued by worker threads with data
* event loop threads call this methods
* this is where the main bottleneck is in case of Node.js
* if your callback have any consuming task lets say loop
* of 1M then you Event loop will be busy and you can't
* accept new connection. In practice in memory computation
* are very fast as compared to network io.
*/
executeCallBackMethodsfromQueue();
}
现在你看到上面的方法可以接受比每个请求线程模型更多的连接
工作线程也不会被卡住,因为它们只会读取那些有数据的连接。当工作线程读取整个数据时,它们将使用您在侦听时提供的回调处理程序将响应或数据排队到队列中。该回调方法将再次由事件循环线程执行。
上述方法有两个缺点。
- 无法正确使用多处理器的所有核心。
- 长时间内存计算会显着降低性能。
第一个缺点可以通过集群 Node.js 来解决,即与 cpu 的每个核心相对应的一个 Node.js 进程。
无论如何,看看 vert.x,它有点类似 node.js,但用的是 java。
还可以探索 Netty。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)