使用带有套接字的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数据包。