如何研究Java插座程序性能问题



我有两种变体的Java程序[server.java and Client.java]和[servertest.java and Clienttest.java]。他们都做同样的事情,客户端连接到服务器,并将整数对发送到服务器以进行乘,结果返回给客户端,然后将其打印。这是每次执行100次。

但是,在测试版本中,我为整数对的每次段落及其乘法创建并关闭一个新的套接字(执行100个乘法)。在普通版本中,我打开一个持久插座,并与客户端执行所有交互,然后关闭。

直觉上,我认为创建一个持久套接字的方法比每次创建,接受和关闭插座的速度要快一点 - 实际上,在创建,接受和关闭的新插座的方法中,明显更快。平均而言,持续的套接字方法大约需要8秒,而每次都需要0.4秒就会创建新套接字的方法。

我检查了两者的系统调用活动,并注意到两者之间没有什么不同。然后,我在另一台计算机(Macos Sierra)上测试了相同的程序,两者之间的区别可忽略不定。因此,似乎问题甚至不在应用程序代码,而是如何与OS进行交互(我正在运行Ubuntu LTS 16.04)。

有人知道为什么这里的性能存在如此差异,还是如何进一步调查问题?执行程序时,我还检查了系统宽指标(内存使用和CPU使用),并且似乎有很多内存,并且CPU的时间有很多空闲时间。


请参阅两种方法如何不同的代码段:

每次方法创建新套接字:

// this is called one hundred times
public void listen() {
    try {
        while (true) {
            // Listens for a connection to be made to this socket.                                        
            Socket socket = my_serverSocket.accept();
            DataInputStream in = new DataInputStream(socket
                    .getInputStream());
            // Read in the numbers
            int numberOne = in.readInt();
            int numberTwo = in.readInt();
            int result = numberOne * numberTwo;
            DataOutputStream out = new DataOutputStream(socket.getOutputStream());
            out.writeInt(result);
            // tidy up
            socket.close();
        }
    } catch (IOException ioe) {
        ioe.printStackTrace();
    } catch (SecurityException se) {
        se.printStackTrace();
    }
}

持久套接字方法:

public void listen() {
    try {
        while (true) {
            // Listens for a connection to be made to this socket.
            Socket socket = my_serverSocket.accept();
            for (int i = 0; i < 100; i++) {
                DataInputStream in = new DataInputStream(socket
                        .getInputStream());
                // Read in the numbers
                int numberOne = in.readInt();
                int numberTwo = in.readInt();
                int result = numberOne * numberTwo;
                DataOutputStream out = new DataOutputStream(socket.getOutputStream());
                out.writeInt(result);
            }
            // tidy up
            socket.close();
        }
    } catch (IOException ioe) {
        ioe.printStackTrace();
    } catch (SecurityException se) {
        se.printStackTrace();
    }
}

您没有向我们展示发送整数以进行乘法的代码。您是否碰巧有一个循环,在每次迭代中,您发送一对并接收结果?如果是这样,请确保关闭Nagle的算法。

Nagle的算法试图克服"小包装问题",即当应用程序反复在小块中排放数据时。这导致了巨大的开销,因为数据包标头通常比数据本身大得多。该算法实质上结合了许多小消息,并立即发送它们。如果收集了足够的数据,则该算法仍然可能会发送消息,但只有在某些超时已通过。

在您的情况下,您在客户端和服务器端的套接字上写了一小部分数据。数据未立即传输。而是插座等待更多数据来(没有),因此每次超时都必须经过。

实际上,这2件代码之间的唯一区别不是它们处理传入连接的方式(是否有一个持久的插座),区别在于,您称之为的连接"持续的",100对数量乘以,而在另一个数字中,只有1对数字被乘以返回。这可以解释时间的差异。

最新更新