2011年的Java:线程套接字VS NIO:在64位操作系统和最新的Java版本上可以选择什么?

时间:2011-03-25 20:21:48

标签: java networking io nio

我在StackOverflow和一些博客上阅读了几篇关于java.net vs java.nio的帖子。但我仍然无法理解何时应该更喜欢NIO而不是螺纹插座。你能否在下面检查我的结论并告诉我哪些不正确以及哪些错过了?

  • 因为在线程模型中你需要为每个活动连接专用一个线程,并且每个线程为它的堆栈占用250Kilobytes的内存,使用每个套接字模型,你将在大量并发连接上快速耗尽内存。与NIO不同。

  • 在现代操作系统和处理器中,可以认为大量活动线程和上下文切换时间对于性能几乎无关紧要

  • NIO的整个吞吐量可能会更低,因为异步NIO库在高负载环境中使用的select()和poll()比唤醒和放入休眠线程更昂贵。

  • NIO一直比较慢,但它允许您处理更多的并发连接。它本质上是一个时间/空间权衡:传统IO速度更快但内存占用更大,NIO速度更慢但使用的资源更少。

  • Java每个并发线程的硬件限制为15000/30000,具体取决于JVM,这会将每个连接模型的线程限制为此并发连接数最大,但JVM7将没有此限制(无法确认此数据)

因此,作为结论,您可以拥有:

  • 如果您有数万个并发连接 - 除非请求处理速度是您的关键因素,否则NIO是更好的选择
  • 如果你的数量少于 - 每个连接的线程是一个更好的选择(假设你可以承受大量的RAM来保持所有并发线程的堆栈达到最大值)
  • 使用Java 7,您可能希望在任何一种情况下都使用NIO 2.0。

我说错了吗?

5 个答案:

答案 0 :(得分:3)

对我来说这似乎是正确的,除了关于Java限制线程数量的部分 - 通常受到运行的操作系统的限制(参见How many threads can a Java VM support?Can't get past 2542 Threads in Java on 4GB iMac OSX 10.6.3 Snow Leopard (32bit))。

要达到那么多线程,您可能需要调整JVM的堆栈大小。

答案 1 :(得分:2)

我仍然认为传统IO中线程的上下文切换开销很大。在较高级别,如果他们不会争用相同的资源,或者他们花费的时间远远高于资源上下文切换开销,那么您只能使用多个线程获得性能。 提出这个问题的原因是,使用像SSD这样的新存储技术,你的线程会更快地在CPU上竞争

答案 2 :(得分:0)

没有一种“最好”的方式来构建NIO服务器,但这个特定问题在SO上的优势表明人们认为存在!您的问题总结了适合这两个选项的用例,以帮助您做出适合您的决定。

此外,混合解决方案也是可能的!当他们要做一些值得付出代价的事情时,你可以将频道交给线程,并在更好的情况下坚持使用NIO。

答案 3 :(得分:0)

我会说从每个连接线程开始,如果遇到问题就从那里进行调整。

如果你真的需要处理一百万个连接,你应该考虑在C(或其他)中编写(或找到)一个简单的请求代理,每个连接使用的内存远远少于任何java实现。代理可以异步接收请求,并将它们排队到以您选择的语言编写的后端工作人员。

后端因此每个活动请求只需要一个线程,并且您可以只有一个固定数量的线程,因此在某种程度上预先确定了内存和数据库的使用。当大量请求并行运行时,请求会等待一段时间。

因此,我认为您永远不必在64位系统上使用NIO选择通道或异步I / O(NIO 2)。每个连接线程模型运行良好,您可以使用一些更合适的低级技术扩展到“数十或数十万”连接。

避免过早优化(即在真正有大量连接进入之前编写NIO代码)总是有帮助的,如果可能的话,不要重新发明轮子(Jetty,nginx等)。

答案 4 :(得分:0)

最常被忽视的是NIO允许零拷贝处理。例如。如果您使用单个服务器上的旧学校套接字从多个进程内侦听相同的多播流量,则会将任何多播数据包从网络/内核缓冲区复制到每个侦听应用程序。因此,如果您构建一个GRID,例如20个进程,就会出现内存带宽问题。使用nio,您可以检查传入缓冲区,而无需将其复制到应用程序空间。然后,该过程仅复制其感兴趣的部分传入流量。

另一个应用示例: 有关示例,请参阅http://www.ibm.com/developerworks/java/library/j-zerocopy/