最近我在玩Java套接字和NIO来编写服务器。虽然我仍然不太清楚为什么Java NIO可以优于标准套接字。使用这些技术中的任何一种编写服务器时,在大多数情况下,它归结为具有接受连接的调度程序线程并进一步将它们传递给工作线程。
我已经读过在线程模型中我们需要每个连接一个专用线程,但我们仍然可以创建一个固定大小的线程池并重用它们来处理不同的连接(这样就会产生创建和拆除线程的成本减少了。)
但是使用Java NIO看起来很相似。我们有一个线程接受请求,一些工作线程在接收到数据时处理数据。
我发现Java NIO会更好的一个例子是维护许多非忙连接的服务器,如聊天客户端或http服务器。但不能真正理解为什么。
答案 0 :(得分:3)
有几个不同的原因。
将多路复用I / O与Selector
一起使用可以节省大量线程,从而节省大量线程堆栈,从而节省大量内存。另一方面,它将调度从操作系统移动到您的程序中,因此它可能会花费您一些CPU,并且还会花费您很多的编程复杂性。鉴于select()是在替代方案是更多进程而不是更多线程时设计的,实际上有争议的是额外的复杂性是否真的值得,而不是使用线程并将编程资金花在更多内存上。
MappedByteBuffers
是一种比java.io或java.nio.channels
使用ByteBuffers
更快的文件阅读方式。
如果您只是从一个通道复制到另一个通道,使用“直接”缓冲区可以使您不必将数据从本机JNI空间复制到JVM空间并再次返回;或者使用FileChannel.transferTo()方法可以避免将数据从内核空间复制到用户空间。
答案 1 :(得分:1)
即使NIO支持Dispatcher模型,默认情况下NIO套接字阻塞,当您使用它们时,它们可以比普通IO或非阻塞NIO更快(对于小型)(< 100)连接。我还发现阻止NIO比非阻塞NIO更容易使用。
当我想使用忙等待时,我使用非阻塞NIO。这允许有一个永不放弃CPU的线程,但这仅在极少数情况下有用,即延迟是不可避免的。
答案 2 :(得分:0)
从我的基准测试来看,真正的优势(除了线程模型之外)是它消耗更少的内存带宽(Kernel< => Java)。例如。如果您打开多个UDP NIO多播通道并具有高流量,您会注意到在每个新进程的特定数量的进程中,所有正在运行的UDP接收器的吞吐量都会降低。使用传统的套接字API,我启动3个接收进程,具有完全吞吐量。如果我从第4开始,我达到了限制,并且在所有正在运行的进程中接收的数据/秒将降低。使用nio,我可以开始大约6个进程,直到这个效果开始。
我认为这主要是因为NIO直接桥接到本机或内核内存,而旧套接字将缓冲区复制到VM进程空间。
在GRID计算和高负载服务器应用程序(10GBit网络或infiniband)中很重要。