10

我正在尝试使用 Java 中的套接字和对象流进行本地 IPC,但是我发现性能很差。

我正在测试通过 ObjectOutputStream 发送对象到通过 Socket 通过 ObjectInputStream 接收回复的 ping 时间。

这是请求者:

public SocketTest(){

    int iterations = 100;
    try {
        Socket socket = new Socket("localhost", 1212);

        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream()); 
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream()); 

        double start = System.currentTimeMillis();
        for (int i = 0; i < iterations; ++i) {

            Request request = new Request();
            objectOutputStream.writeObject(request);

            Response response = (Response)objectInputStream.readObject();
        }
        double finish = System.currentTimeMillis();
        System.out.println("Per ping: " + (finish - start) / iterations );

    } catch (Exception e) {
        e.printStackTrace();
    }
}

这是响应者:

public ServerSocketTest(){

    try {

        ServerSocket serverSocket = new ServerSocket(1212);
        Socket socket = serverSocket.accept();

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());

        Request request = (Request)objectInputStream.readObject();
        while (request != null) {

            Response response = new Response();
            objectOutputStream.writeObject(response);
            request = (Request)objectInputStream.readObject();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

我得到的结果是:

每平:80.35

对于本地流量来说,80 毫秒的速度太慢了。

Request 和 Response 类非常小,它们的序列化速度很快。

我曾尝试天真地添加:

socket.setKeepAlive(true);  
socket.setTcpNoDelay(true);

影响不大。

执行 ping 本地主机:

64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=0 ttl=64 time=0.035 ms  
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=1 ttl=64 time=0.037 ms  
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=2 ttl=64 time=0.049 ms  
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=3 ttl=64 time=0.039 ms  
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=4 ttl=64 time=0.056 ms  

也很快。

Java 版本 1.6.0_05l 在 RedHat 2.4 上运行

4

5 回答 5

5

您是否尝试过在BufferedInputStream / BufferedOutputStream中同时嵌入请求和响应?它应该广泛地提高性能。

于 2010-02-12T10:27:47.343 回答
1

因此,在构造 BufferedInputStream 之前构造 BufferedOutputStream 并刷新它。避免挂起。

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4788782

它说根据文档

如果您修改测试用例,使得 AServer 和 AClient 在 ObjectInputStream 之前构造 ObjectOutputStream,则测试不会阻塞。这是给定以下文档的预期行为:

ObjectOutputStream 构造函数:
创建一个写入指定
OutputStream 的 ObjectOutputStream。此构造函数将序列化流标头写入底层流;调用者可能希望立即刷新流,以确保接收
ObjectInputStreams 的构造函数在读取标头时不会阻塞。

ObjectInputStream 构造函数:
创建一个从指定
InputStream 读取的 ObjectInputStream。从流中读取序列化流标头并进行验证。此构造函数将阻塞,直到相应的
ObjectOutputStream 已写入并刷新标头。

于 2010-03-25T16:23:11.843 回答
0

除了在每次读取之前使用缓冲流并调用 flush() 之外,您还应该首先在两端创建 ObjectOutputStream。此外,测试返回 null 的 readObject() 是没有意义的,除非您打算调用 writeObject(null)。使用 readObject() 对 EOS 的测试是 catch (EOFException exc)。

于 2010-02-15T00:26:50.210 回答
0

我仍然认为它会比那更快。我还能做些什么来改善这一点吗?

这似乎是一个微基准。它们总是很难正确处理,但我认为如果您在开始延迟测量之前先发送 2000 条消息。

另外,请参阅有关如何正确进行微基准测试的详细答案

于 2010-10-03T15:31:46.950 回答
-1

我希望您必须致电objectOutputStream.flush()双方以确保数据立即发送到网络。否则,TCP 堆栈可能会等待一段时间以等待更多数据来填充部分 IP 数据包。

于 2010-02-12T10:35:29.703 回答