使用带有套接字的 Java 对象流的性能问题
我正在尝试使用 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();
}
}
我得到的结果是:
每 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 上运行
I'm trying to do local IPC using Sockets and Object streams in Java however I'm seeing poor performance.
I am testing the ping time of sending an object via an ObjectOutputStream to receiving a reply via an ObjectInputStream over a Socket.
Here's the Requestor:
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();
}
}
Here's the responder:
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();
}
}
The result I'm getting is:
Per ping: 80.35
80 msec is far to slow for local traffic.
Request and Response classes are very small and their serialisation is fast.
I have tried naively adding:
socket.setKeepAlive(true);
socket.setTcpNoDelay(true);
with little effect.
performing a 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
is also fast.
Java version 1.6.0_05l
Running on RedHat 2.4
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您是否尝试过在 BufferedInputStream 中嵌入请求和响应/BufferedOutputStream ?它应该广泛提高性能。
Have you tried embedding both reques ts and responses in BufferedInputStream/BufferedOutputStream ? It should widely improve performances.
所以构造BufferedOutputStream &在构造 BufferedInputStream 之前刷新它。以免悬挂。
https://bugs.java.com/bugdatabase/view_bug?bug_id=4788782
根据文档说明
So construct the BufferedOutputStream & flush it before constructing the BufferedInputStream. To avoid hanging.
https://bugs.java.com/bugdatabase/view_bug?bug_id=4788782
it says as per documentation
除了使用缓冲流并在每次读取之前调用flush()之外,您还应该首先在两端创建ObjectOutputStream。另外,测试 readObject() 返回 null 是没有意义的,除非您打算调用 writeObject(null)。使用 readObject() 对 EOS 进行的测试是 catch (EOFException exc)。
In addition to using Buffered streams and calling flush() before every read, you should also create the ObjectOutputStream first at both ends. Also, testing for readObject() returning null is pointless unless you're planning to call writeObject(null). The test for EOS with readObject() is catch (EOFException exc).
这看起来像是一个微基准。它们总是很难正确,但我认为如果您在开始延迟测量之前先发送 2000 条消息。
另请参阅此关于如何正确进行微基准测试的详细答案。
This seems like something of a micro-benchmark. They're always hard to get right, but I think if you start by sending say 2000 messages before starting your latency measurements.
Also, see this detailed answer on how to do micro-benchmarks right.
我希望您必须在两侧调用
objectOutputStream.flush()
以确保数据立即发送到网络。否则,TCP 堆栈可能会等待一段时间以获取更多数据来填充部分 IP 数据包。I would expect that you have to call
objectOutputStream.flush()
on both sides to ensure that the data is immediately sent to the network. Otherwise, the TCP stack may wait a while for more data to fill a partial IP packet.