使用带有套接字的Javas对象流的性能问题

我正在尝试使用Java中的套接字和对象流来进行本地IPC,但是我看到性能不佳。

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

这是请求者:

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(); } } 

我得到的结果是:

Per ping:80.35

对于当地交通来说,80毫秒的速度非常慢。

请求和响应类非常小,并且它们的序列化很快。

我试过天真添加:

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

影响不大。

执行ping localhost:

 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上运行

您是否尝试在BufferedInputStream / BufferedOutputStream中嵌入请求ts和响应? 它应该广泛改善表现。

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

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

它根据文件说

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

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

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

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

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

这似乎是一个微观基准。 他们总是很难做对,但我想如果你开始在开始延迟测量之前发送说2000消息。

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

我希望您必须在两侧调用objectOutputStream.flush()以确保数据立即发送到网络。 否则,TCP堆栈可能需要等待一段时间才能有更多数据填充部分IP数据包。