如何调查Java套接字程序性能问题

时间:2017-12-20 17:29:48

标签: java performance sockets

我有两组相同的Java程序[Server.java和Client.java]和[ServerTest.java和ClientTest.java]。它们都做同样的事情,客户端连接到服务器并将整数对发送到服务器以进行相乘,结果返回到客户端,然后打印出来。每次执行100次。

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

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

我检查了两者的系统调用活动,并注意到两者之间没有任何不同。然后我在另一台计算机(macOS Sierra)上测试了相同的程序,两者之间存在着可忽略的差异。因此,问题似乎不在于应用程序代码,而在于它与操作系统的交互方式(我正在运行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();
    }
}

2 个答案:

答案 0 :(得分:1)

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

Nagle的算法试图克服&#34;小数据包问题&#34;,即当应用程序以小块重复发射数据时。这导致巨大的开销,因为数据包标头通常比数据本身大得多。该算法基本上组合了许多小的外发消息并一次性发送它们。如果没有收集到足够的数据,那么算法仍然可以发送消息,但仅在某个超时已经过去时才会发送。

在您的情况下,您正在将小块数据写入客户端和服务器端的套接字中。数据没有立即传输。相反,套接字等待更多的数据(它没有),所以每次超时都要过去。

答案 1 :(得分:0)

实际上,这2段代码之间的唯一区别不在于它们如何处理传入连接(通过有一个持久性套接字),区别在于你称之为“持久性”的那个,100对数字是乘以,而在另一个中,只有1对数相乘然后返回。这可以解释时间上的差异。