0

現在、分散アプリケーションのパフォーマンスに取り組んでいます。ネットワーク コンポーネントをターゲットにしています。現在、接続ごとに、ブロッキング モードでソケットを処理する専用スレッドがあります。私の目標は、(パフォーマンスを低下させることなく) スレッドの数を減らし、可能であればパフォーマンスを向上させることです。

非同期通信を使用するようにネットワーク コンポーネントを再設計し、ネットワーク処理全体に 1 ~ 2 スレッドを使用しようとしています。あるノードからループで書き込み、別のノードで読み取る簡単なテストを行いました。これは、最大 nw スレッド機能をテストするためであり、ビジー ループの実装が 100% の CPU を消費し、1 秒あたりの操作数がはるかに多いことがわかりました。必要とする。そこで、このビジー ループの実装を既存のアプリケーションに統合しました。

私が見つけた問題は、8 コア システムを使用していて、400% 以上の CPU を使用していないにもかかわらず、他のスレッドがこれらの非同期 nw スレッドがフル CPU を取得することを許可していないことです。基本的に C プログラマーである私は、nw スレッドをコアにバインドし、そのスケジューリング優先順位を上げることでこれを解決し、他のスレッドが他のコアで引き続き実行できるようにしました。Javaで同様のことを行うことはできません。Java スレッドの優先順位については、矛盾するコメントがあります。また、独自の副作用がある可能性があるため、他のスレッドの優先度を下げたくありません。

この問題をどのように解決しますか?

4

2 に答える 2

3

Linux および Windows 上の Java でスレッド アフィニティをサポートするライブラリがあります。https://github.com/peter-lawrey/Java-Thread-Affinity

CPUを分離すると、割り当てたCPUが他のもの(マスク不可能な割り込み以外)に使用されないようにすることができます。これは、LinuxのAFAIKで最適に機能します。


ブロッキング IO よりも非ブロッキング NIO でビジー待機を使用すると、より低いレイテンシーの結果を得ることができます。後者は負荷がかかった状態で最適に機能しますが、負荷が低いとレイテンシが増加する可能性があります。

このライブラリは興味深いかもしれませんhttps://github.com/peter-lawrey/Java-Chronicleを使用すると、1 秒あたり数百万のメッセージを、オプションで 2 番目のプロセスに永続化できます。

ところで:スレッドの優先度は単なるヒントです。OSはそれを自由に無視できます(そしてしばしば無視します)


ウォーム コードとコールド コードを比較する簡単な例。配列を繰り返しコピーして時間を計るだけです。コードとデータがウォームアップされると、遅くなるとは思わないでしょうが、コピーにかかる時間を大幅に遅くするには、かなりのマシンでも 10 ミリ秒の遅延が必要です。

public static void main(String... args) throws InterruptedException {
    int[] from = new int[60000], to = new int[60000];
    for (int i = 0; i < 10; i++)
        copy(from, to); // warm up
    for (int i = 0; i < 10; i++) {
        long start = System.nanoTime();
        copy(from, to);
        long time = System.nanoTime() - start;
        System.out.printf("Warm copy %,d us%n", time / 1000);
    }
    for (int i = 0; i < 10; i++) {
        Thread.sleep(10);
        long start = System.nanoTime();
        copy(from, to);
        long time = System.nanoTime() - start;
        System.out.printf("Cold copy %,d us%n", time / 1000);
    }
}

private static void copy(int[] a, int[] b) {
    for (int i = 0, len = a.length; i < len; i++)
        b[i] = a[i];
}

版画

Warm copy 20 us
Warm copy 20 us
Warm copy 19 us
Warm copy 23 us
Warm copy 20 us
Warm copy 20 us
Cold copy 100 us
Cold copy 80 us
Cold copy 89 us
Cold copy 92 us
Cold copy 80 us
Cold copy 112 us
于 2012-08-09T17:44:15.467 に答える
1

これは、時期尚早の最適化のように思えます。8 コアのシステムがあり、400% の CPU しか使用していません。これが IO バウンド プログラムの教科書的な例ではないと考える理由は何ですか? ネットワーク IO チェーンを使い果たしていないと思う理由は何ですか?

@Peterは彼のことを知っており、プロセッサアフィニティをハックして、重要なスレッドを単一のCPUに強制できると確信していますが、問題は、プログラムの実行が速くなるかどうかです? 私は心からそれを疑います。モデルの Java VM は、スレッドのスケジューリングに関して非常にスマートであり、その仕事を適切に行っていることをお勧めします。それとは反対の非常に良い証拠がない限り、スケジューリングは任せます。ほとんどのスレッドが IO を待機している場合、優先度を設定してもほとんど意味がありません。

また、スレッド数を減らした方がなんとなくいいと思われるのはなぜでしょうか。これにより、多くのコードがネイティブ ランド (つまり、スレッドの多重化) から Java ランド (つまり、NIO コード) に移動します。数千のスレッドについて話している場合は同意しますが、数百のスレッドでも接続を処理する効率的な方法である必要があります。

私は 20 年以上にわたって大量のスレッド プログラミングを行ってきましたが、スレッド アフィニティを強制する必要はありませんでした。確かに、スレッドプールのサイズを決定し、スレッドプールと専用スレッドをどこに適用するかを適切に決定することは芸術ですが、VM にスレッドをスケジュールするように強制することは、時間の有効な使い方ではありません。プロファイラーを使用して、プログラムが時間を費やしている場所を見つけることは、私見のより良い投資になるでしょう。

于 2012-08-10T01:10:48.180 に答える