与Java中的传统IO相比,NIO性能改进

我看过许多文章/博客说与传统的Java IO相比,Java NIO是一个更好的解决方案。

但今天我的一位同事向我展示了这个博客http://mailinator.blogspot.com/2008/02/kill-myth-please-nio-is-not-faster-than.html 。 我想知道Java社区中是否有人做过与Java NIO性能相关的这种基准测试。

NIO vs IO是一个非常有趣的话题要讨论。

根据我的经验,这两种工具是两种不同的工具,可用于两种不同的工作。 我听说IO被称为“每个客户的线程”方法,而NIO被称为“所有客户的一个线程”方法,我发现这些名称虽然不是100%准确,但足够合适。

正如我所看到的,NIO和IO的真正问题在于可扩展性。

NIO网络层将(应该?)使用单个线程来处理选择器并将读/写/接受作业分派给其他线程。 这允许处理选择器的线程(“选择器线程”)除此之外什么都不做。 这样可以在处理大量客户(请注意缺少实际数量)时更快地响应。 现在,NIO开始崩溃的时候是服务器获得如此多的读/写/接受,而选择器线程一直在工作。 过去这个和服务器的任何其他工作都开始滞后。 此外,由于所有读/写/接受作业都由选择器线程处理,因此在混合中添加额外的CPU不会提高性能。

IO网络层可能会采用每个套接字1个线程的方法,包括侦听套接字。 因此线程数与客户端数量成正比。 在适量的客户下,这种方法非常有效。 通过使用这种方法支付的成本以线程成本的forms出现。 如果您有2000个客户端连接到服务器…您至少有2001个线程。 即使在四芯片中,每个芯片机器有6个核心,你只需要24个处理节点(如果算上超线程就有48个)来处理这些2001线程。 实例化所有这些线程会花费cpu time和ram,但即使你使用线程池,你仍然需要支付CPU上下文切换的成本,因为它们从一个线程移动到线程。 这可能会在高服务器负载下变得非常难看,如果编码不正确,可能会使整个机器停止运行。 从好的方面来说,在这种情况下,将CPU添加到机器将提高性能。

现在一切都很好,但是很抽象,因为我的描述中没有数字可以帮助决定使用IO或NIO。 这是因为还有更多变量需要考虑:

  • 客户的生命时间? 短期还是长期?
  • 每个客户预计的数据量? 很多小块或几块巨大的块?
  • 预计会同时连接多少客户端?
  • 您使用的是什么操作系统以及您使用的JVM是什么? 这两个因素分为线程和轮询成本。

只是一些值得思考的东西。 要回答哪个问题更快,NIO或IO:两者兼而有之:)

AB快, 往往是一个非常简单的观点, 有时候是错误的。

NIO 不会比普通IO自动更快。

使用NIO 可能会更快地进行某些操作,并且使用NIO可以更轻松地扩展到许多网络连接(因为每个连接不需要一个线程)。

但NIO并不是一个神奇的“让事情变得更快” – 需要应用于一切的开关。

使用NIO不是因为它更快,而是因为它具有更好的可扩展性,尤其是有大量的客户端。

IO(阻塞IO /流IO)通常是每个连接一个线程 ,以便更好地响应客户端。 假设您使用单线程(阻止)监听/(阻止)读取/处理/(阻止)写入所有客户端,就像星巴克在一个窗口中为所有客户服务一样,星巴克客户(您的客户)会变得不耐烦(超时) )。

请注意,您可以考虑使用线程池来避免大量线程拖拽您的服务器。 虽然它就像星巴克将所有客户分成几个窗口,但客户仍因其他人的阻塞而延迟。 这就是为什么每个连接一个线程是传统java IO编程中的一个很好的选择。

NIO(无阻塞IO /块IO 使用哪一个 )使用Reactor Pattern来处理IO事件。 在这种情况下,您可以使用单线程来阻止/侦听|读取|处理|写入 。 然后阻塞(等待期)的客户端不会相互影响。

注意IO和NIO都可以使用multithreading来利用更多的cpu资源, Doug lee介绍的更多细节。

你引用的文章是三岁。 它使用Java 1.4.2(4)。

从那时起,Java 5,6和现在的7都出局了。

JVM和类库内部的巨大变化使得与1.4.2基准测试无关的任何事情都变得无关紧要。

如果你开始挖掘,你还会注意到java.io和java.nio之间的区别并不是那么清楚。 许多java.io调用现在解析为java.nio类。

但无论何时你想要提高性能,解决方案都不是做任何事情。 确切知道的唯一方法是尝试不同的技术并测量它们,因为我的应用程序的速度对于您的应用程序来说并不一定如此,反之亦然。 对于某些应用程序,NIO可能会慢一些。 或者它可能是性能问题的解决方案。 最有可能的是,它们都是两者兼而有之。

该文章的问题是它将阻塞IO与非阻塞NIO进行比较。 在我自己的测试中,比较阻塞IO与阻塞NIO(更喜欢类似),NIO的速度提高了30%。

但是,除非您的应用程序是微不足道的,如代理服务器,否则它不太重要。 应用程序的作用更为重要。 IO和NIO都经过了多达10,000个连接的测试。

如果你想要超快的IO你可以使用Infiniband的Asynch IO(Java 7+)(不便宜,但延迟更低)

此外,AFAIK,Java IO被重写为使用NIO(并且NIO具有更多function)。 微缩胶片只是一个坏主意,特别是当他们年老时,就像拉维尼奥所说的那样。

Java NIO被认为比常规IO更快,因为:

  1. Java NIO支持非阻塞模式。 非阻塞IO比阻塞IO更快,因为它不需要每个连接一个专用线程。 当您需要处理大量同时连接时,这可以显着提高可伸缩性,因为线程不是很可伸缩。

  2. Java NIO通过支持直接内存缓冲区来减少数据复制。 可以读取和写入NIO套接字而无需任何数据复制。 使用传统的Java IO,数据在套接字缓冲区和字节数组之间被多次复制。

Java NIO和reactor模式本身并不太关乎网络性能,而是关于单线程模型在性能和简单性方面可以为系统提供的优势。 而且,单线程方法可以带来显着的改进。 看看这里: 插槽间通信,延迟小于2微秒

Java IO包含了几个构造和类。 你无法在这样的一般水平上进行比较。 具体来说,NIO使用内存映射文件进行读取 – 理论上预计这比简单的BufferedInputStream文件读取要快一些。 但是,如果你比较一个像RandomAccess文件读取的东西,那么NIO内存映射文件会快得多。

一个人比另一个人更快,没有固有的原因。

每线程一个连接模型目前正遭受Java线程具有大量内存开销的事实 – 线程堆栈预先分配到固定(和大)的大小。 这可以而且应该是固定的; 然后我们可以廉价地创建数十万个线程。