13

何千ものネットワーク リクエストを作成するユーティリティを作成しています。各要求は、応答として 1 つの小さなパケットのみを受信しますが (ping と同様)、完了するまでに数秒かかる場合があります。各応答の処理は、1 行の (単純な) コードで完了します。

これの最終的な効果は、コンピューターが IO バウンド、ファイル システム バウンド、または CPU バウンドではなく、応答の待機時間によってのみバインドされることです。

これは、理想的なスレッド数を決定する方法はありますか?と似ていますが、同じではありません。およびJavaの最適なスレッド数を決定する最良の方法[重複] ...主な違いは、レイテンシーのみに拘束されることです。

ExecutorServiceオブジェクトを使用してスレッドを実行し、Queue<Future<Integer>>結果を取得する必要があるスレッドを追跡します。

ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize);
Queue<Future<Integer>> futures = new LinkedList<Future<Integer>>();

for (int quad3 = 0 ; quad3 < 256 ; ++quad3) {
    for (int quad4 = 0 ; quad4 < 256 ; ++quad4) {
        byte[] quads = { quad1, quad2, (byte)quad3, (byte)quad4 };
        futures.add(executorService.submit(new RetrieverCallable(quads)));
    }
}

... 次に、キュー内のすべての要素をデキューし、結果を必要なデータ構造に入れます。

int[] result = int[65536]
while(!futures.isEmpty()) {
    try {
        results[i] = futures.remove().get();
    } catch (Exception e) {
        addresses[i] = -1;
    }
}

私の最初の質問は、これはすべてのスレッドを追跡する合理的な方法ですか? スレッド X の完了に時間がかかる場合、他の多くのスレッドが X より先に終了する可能性があります。スレッド プールは、開いているスロットを待ってそれ自体を使い果たしますか? または、ExecutorServiceオブジェクトは、完了したがまだ処理されていないスレッドを使用可能なスロットから移動して、他のスレッドを開始できるようにプールを管理しますか?

2 番目の質問は、これらの呼び出しを行うのに最適なスレッド数を見つけるために、どのガイドラインを使用できるかということです。ここでは桁違いのガイダンスさえ知りません。256 スレッドでうまく動作することはわかっていますが、1024 スレッドでも全体的にほぼ同じ時間がかかるようです。CPU 使用率は 5% 前後で推移しているため、問題はないようです。このように多数のスレッドがある場合、さまざまな数値を比較するために見なければならないすべてのメトリックは何ですか? 明らかに、バッチを処理するための全体的な時間、スレッドあたりの平均時間...他に何がありますか? ここでメモリは問題ですか?

4

7 に答える 7

7

あなたが参照するリンクされた回答の 1 つで述べたように、Brian Goetzは彼の記事でこれをよくカバーしています。

彼は、あなたの状況では、スレッド数にコミットする前にメトリックを収集することをお勧めすることを暗示しているようです.

プールサイズのチューニング

スレッド プールのサイズを調整することは、主に 2 つの間違い (スレッドが少なすぎる、またはスレッドが多すぎる) を回避することです。...

スレッド プールの最適なサイズは、使用可能なプロセッサの数と作業キューのタスクの性質によって異なります。...

I/O の完了を待機する可能性のあるタスク (ソケットから HTTP 要求を読み取るタスクなど) の場合、すべてのスレッドが機能するわけではないため、使用可能なプロセッサの数を超えてプール サイズを増やす必要があります。常に。プロファイリングを使用すると、一般的なリクエストの待機時間 (WT) とサービス時間 (ST) の比率を見積もることができます。この比率を WT/ST と呼ぶ場合、N プロセッサ システムの場合、プロセッサを十分に活用するには、およそ N*(1+WT/ST) スレッドが必要になります。

私の強調。

于 2013-10-24T10:18:15.783 に答える
3

Actors の使用を検討しましたか?

ベスト プラクティス。

  • アクターは素敵な同僚のようであるべきです。他の人に不必要に迷惑をかけることなく効率的に仕事をし、リソースを浪費しないようにします。プログラミングに翻訳すると、これはイベントを処理し、イベント駆動型の方法で応答 (または複数の要求) を生成することを意味します。アクターは、やむを得ない場合を除き、何らかの外部エンティティ (ロック、ネットワーク ソケットなど) をブロックする (つまり、スレッドを占有している間、受動的に待機する) べきではありません。後者の場合は、以下を参照してください。

申し訳ありませんが、これはあまり使用していないため、詳しく説明できません。

アップデート

Akka の適切な使用例の回答が役立つ場合があります。
Scala: なぜアクターは軽量なのですか?

于 2013-10-24T10:12:38.743 に答える
1

望ましい最適化は、すべてのリクエストを処理する時間だと思います。リクエスト数は「数千」とおっしゃいましたね。明らかに、最速の方法はすべてのリクエストを一度に発行することですが、これはネットワーク レイヤーをオーバーフローする可能性があります。ネットワーク層が耐えられる同時接続数を決定し、この数をプログラムのパラメータにする必要があります。

次に、リクエストごとにスレッドを消費すると、大量のメモリが必要になります。これは、ノンブロッキング ソケットを使用して回避できます。Java には、セレクターを使用する NIO1 と非同期チャネルを使用する NIO2 の 2 つのオプションがあります。NIO1 は複雑なので、既製のライブラリを見つけて再利用することをお勧めします。NIO2 は単純ですが、JDK1.7 以降でのみ使用できます。

応答の処理は、スレッド プールで行う必要があります。あなたの場合、スレッドプール内のスレッドの数が全体的なパフォーマンスに大きく影響するとは思いません。スレッド プール サイズを 1 から使用可能なプロセッサの数まで調整するだけです。

于 2013-10-24T11:21:29.320 に答える
1

私たちの高性能システムでは、@Andrey Chaschev によって説明されているように、アクター モデルを使用します。

いいえ。アクター モデルの最適なスレッドの数は、CPU 構造と、ボックスごとに実行するプロセス (JVM) の数によって異なります。私たちの発見は

  1. プロセスが 1 つしかない場合は、合計 CPU コア - 2 を使用します。
  2. 複数のプロセスがある場合は、CPU 構造を確認してください。ないのが良いことがわかりました。スレッド数 = いいえ。たとえば、各サーバーに 4 つのコアを持つ 4 つの CPU サーバーがある場合、JVM ごとに 4 つのスレッドを使用すると、最高のパフォーマンスが得られます。後は、OS に最低 1 コアは必ず残しておいてください。
于 2013-10-24T11:05:02.470 に答える
0

部分的な回答ですが、お役に立てば幸いです。はい、メモリが問題になる可能性があります。Java はデフォルトで 1 MB のスレッド スタックを予約します (少なくとも Linux amd64 では)。そのため、ボックスに数 GB の RAM があれば、スレッド数は数千に制限されます。

のようなフラグでこれを調整できます-XX:ThreadStackSize=64。これで 64 kB が得られますが、これはほとんどの状況で十分です。

また、スレッド化を完全にやめて、 epoll を使用して着信応答に応答することもできます。これははるかにスケーラブルですが、Java でこれを行う実際の経験はありません。

于 2013-10-24T09:46:58.453 に答える