Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么JavaNIO可以优于标准JavaSocket?_Java_Sockets_Nio - Fatal编程技术网

为什么JavaNIO可以优于标准JavaSocket?

为什么JavaNIO可以优于标准JavaSocket?,java,sockets,nio,Java,Sockets,Nio,最近,我正在使用Java套接字和NIO编写服务器。尽管我仍然不清楚为什么JavaNIO会优于标准套接字。当使用这两种技术中的任何一种编写服务器时,在大多数情况下,它归结为拥有一个接受连接并将其进一步传递给工作线程的调度程序线程 我已经读到,在线程模型中,每个连接都需要一个专用线程,但我们仍然可以创建一个固定大小的线程池,并重用它们来处理不同的连接(从而降低创建和拆卸线程的成本) 但是对于JavaNIO,它看起来很相似。我们有一个线程接受请求,还有一些工作线程在接收数据时处理数据 我发现JavaN

最近,我正在使用Java套接字和NIO编写服务器。尽管我仍然不清楚为什么JavaNIO会优于标准套接字。当使用这两种技术中的任何一种编写服务器时,在大多数情况下,它归结为拥有一个接受连接并将其进一步传递给工作线程的调度程序线程

我已经读到,在线程模型中,每个连接都需要一个专用线程,但我们仍然可以创建一个固定大小的线程池,并重用它们来处理不同的连接(从而降低创建和拆卸线程的成本)

但是对于JavaNIO,它看起来很相似。我们有一个线程接受请求,还有一些工作线程在接收数据时处理数据


我发现JavaNIO更好的一个例子是一个服务器,它维护许多非繁忙的连接,比如聊天客户端或http服务器。但是我真的不明白为什么。

从我的基准测试来看,真正的优势(除了线程模型)是,它使用更少的内存带(内核Java)。例如,如果您打开多个UDP NIO多播通道,并且具有高流量,您将注意到,在具有每个新进程的特定数量的进程中,所有正在运行的UDP接收器的吞吐量都会降低。使用传统的socket API,我启动了3个满吞吐量的接收进程。如果我启动第四个进程,我将达到一个极限,并且在所有正在运行的进程上每秒接收的数据将降低。使用nio,我可以启动大约6个进程,直到这个效果开始

我认为这主要是因为NIO直接桥接到本机或内核内存,而旧的套接字将缓冲区复制到VM进程空间


在网格计算和高负载服务器应用程序(10GBit网络或infiniband)中非常重要。

即使NIO支持Dispatcher模型,NIO套接字在默认情况下是阻塞的,当您这样使用它们时,对于小型(<100)连接,它们可以比普通IO或非阻塞NIO更快。我还发现使用阻塞NIO比使用非阻塞NIO更简单


当我想使用忙等待时,我使用非阻塞NIO。这允许be拥有一个永不放弃CPU的线程,但这只在极少数情况下有用,即延迟是周期性的。

有几个不同的原因

  • 使用带有
    选择器的多路I/O可以节省大量线程,从而节省大量线程堆栈,节省大量内存。另一方面,它将调度从操作系统转移到您的程序中,因此它可能会花费您一点CPU,也会使您的编程复杂化。如果select()是在更多进程而不是更多线程的情况下设计的,那么事实上,与使用线程和将节省的编程资金花费在更多内存上相比,额外的复杂性是否值得值得值得讨论

  • mappedbytebuffer
    是一种比java.io或使用
    java.nio.channels
    ByteBuffers
    读取文件稍微快一点的方法

  • 如果您只是从一个通道复制到另一个通道,那么使用“直接”缓冲区可以避免将数据从本机JNI空间复制到JVM空间,然后再复制回来;或者使用FileChannel.transferTo()方法可以避免将数据从内核空间复制到用户空间


  • 请参阅相关问题。当你说阻塞NIO时,你是指阻塞select()方法吗?@Janek不,我的意思是根本不要使用选择器。阻塞NIO不需要它们,对于非阻塞NIO,您可能希望避免使用它们对于阻塞NIO,每个连接有一个读卡器线程,可以扩展到1000个连接。就像普通的木卫一。如果在一个进程上需要10K+连接,那么选择器是有意义的。在Java中,不能将选择器用于阻塞I/O。我发现了另一个原因。请让我知道它是否正确。当我们使用每事件线程模型时,我们可以更好地利用线程。在每个连接的线程模型中,线程可以从线程池中取出,但保持空闲,例如,当连接上没有数据交换时。对于NIO,我们没有这种情况,因为一旦处理了事件,线程就会返回到池中。连接仍然保持打开状态,但如果连接上没有活动,则池中没有线程用于连接。@Janek这不是“另一个”原因:这只是第1点的一个特例:“它为您节省了很多线程”。