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

私が得ている結果は次のとおりです。

ping あたり: 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  

も高速です。

RedHat 2.4 で動作する Java バージョン 1.6.0_05l

4

5 に答える 5

5

BufferedInputStream / BufferedOutputStreamにリクエストとレスポンスの両方を埋め込んでみましたか? これにより、パフォーマンスが大幅に向上するはずです。

于 2010-02-12T10:27:47.343 に答える
1

そのため、BufferedOutputStream を構築し、BufferedInputStream を構築する前にフラッシュします。ぶら下がりを避けるため。

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を作成する必要もあります。また、writeObject(null)を呼び出す予定がない限り、nullを返すreadObject()のテストは無意味です。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 に答える