nonblocking-io vs blocking-io原始数据吞吐量

时间:2012-01-11 10:44:27

标签: java performance io nio

apache HTTPComponent document中有一个声明:

  

与普遍看法相反,NIO在原始数据吞吐量方面的表现明显低于阻止I / O.“

这是真的吗?有人可以更详细地解释一下吗?

的典型用例是什么?
  

请求/响应处理需要解耦

2 个答案:

答案 0 :(得分:3)

当您可以处理请求时,应该使用非阻塞IO,将其分派用于处理某些其他执行上下文(不同的线程,对另一个服务器的RPC调用,其他一些异步机制)并释放Web服务器的线程以处理更多来电请求。当响应处理完成后,将调用响应处理线程,并将响应发送给客户端。

我建议阅读netty documentation以更好地理解这个概念。

至于更高的吞吐量:当您的服务器发送/接收大量数据时,所有这些上下文切换以及在线程之间传递数据都会严重影响整体性能。可以这样想:你收到一个大请求(带有大文件的PUT请求)。您需要做的就是将其保存到磁盘,然后返回OK。开始在线程之间抛出它可能会导致更少的mem-copy操作,如果你只是把它扔到同一个线程的磁盘上就需要了。以异步方式处理此操作不会提高性能:虽然您可以将请求处理线程发布回Web服务器的线程池并让它处理其他请求,但您的主要性能瓶颈是您的磁盘IO,在这种情况下 - 尝试同时保存更多文件只会让事情变慢。

我希望我足够清楚。如果您需要更多解释,请随时在评论中提出更多问题。

答案 1 :(得分:3)

仅当并发请求数相对较少(而不是数十万)时,第一个语句才为真。这都是关于使用多个线程(阻塞)而不是一个或几个线程(非阻塞)。假设您要编写一个仅从远程服务器下载文件的应用程序。如果您的应用程序一次只需要下载一个文件,则只需要一个线程。但是如果你有一个运行数千个HTTP请求的爬虫,那么你需要有数千个线程(或者使用有限数量的线程+ NIO)。对于如此多的线程,问题是上下文切换,这会大大降低应用程序的速度(因此对于这个并发请求的数量,NIO更好)。

但让我们回到你的问题。为什么NIO在原始数据吞吐量方面会变慢?原因是NIO驱动的应用程序使用的CPU时间量。对于阻塞模型中的这种情况,您的代码只做一件事 - 等待数据(它在循环中执行recv()操作)。在NIO应用程序中,逻辑要复杂得多:在循环中,代码使用选择器来选择一组键(涉及Linux上的epoll_wait系统调用,Oracle JVM),然后遍历集合,选择一个通道每个键然后从通道读取数据(OS中的read()操作)。在标准的阻塞模型中,您所做的就是执行recv()系统函数。总结:在这种情况下,NIO驱动的应用程序使用更多的CPU时间并因为更多的系统调用而产生更多的模式切换操作(通过说模式切换我的意思是从用户切换到内核模式)。因此,下载文件所需的时间会更长。