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

发布于 2024-08-21 05:16:17 字数 2438 浏览 5 评论 0原文

我正在尝试使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

月下客 2024-08-28 05:16:17

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

Have you tried embedding both reques ts and responses in BufferedInputStream/BufferedOutputStream ? It should widely improve performances.

狼性发作 2024-08-28 05:16:17

所以构造BufferedOutputStream &在构造 BufferedInputStream 之前刷新它。以免悬挂。

https://bugs.java.com/bugdatabase/view_bug?bug_id=4788782

根据文档说明

如果您修改测试用例,使得
AServer 和 AClient 构造
之前的 ObjectOutputStream
ObjectInputStream,测试没有
堵塞。这是预期的
给出以下行为
文档:

ObjectOutputStream 构造函数:
创建一个写入指定
的ObjectOutputStream
输出流。这个构造函数写的是
序列化流头
底层流;来电者可能会
想要冲洗流
立即确保
用于接收的构造函数
ObjectInputStreams 不会阻塞
读取标题。

ObjectInputStream 构造函数:
创建一个从指定的
读取的ObjectInputStream
输入流。序列化流
从流中读取 header 并
已验证。这个构造函数会阻塞
直到相应的
ObjectOutputStream 已写入并
刷新标题。

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

If you modify the test case such that
both the AServer and AClient construct
the ObjectOutputStream before the
ObjectInputStream, the test does not
block. This is the expected
behaviour given the following
documentation:

ObjectOutputStream constructor:
Creates an ObjectOutputStream that writes to the specified
OutputStream. This constructor writes
the serialization stream header to
the underlying stream; callers may
wish to flush the stream
immediately to ensure that
constructors for receiving
ObjectInputStreams will not block when
reading the header.

ObjectInputStream constructor:
Creates an ObjectInputStream that reads from the specified
InputStream. A serialization stream
header is read from the stream and
verified. This constructor will block
until the corresponding
ObjectOutputStream has written and
flushed the header.

唱一曲作罢 2024-08-28 05:16:17

除了使用缓冲流并在每次读取之前调用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).

蓝礼 2024-08-28 05:16:17

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

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

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

I still would have thought it would be faster than that. Is there anything else I can do to improve this?

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.

海夕 2024-08-28 05:16:17

我希望您必须在两侧调用 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文