如何研究Java套接字程序性能问题

问题描述 投票:1回答:2

我有两组相同的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();
    }
}
java performance sockets
2个回答
1
投票

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

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

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


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.