私はJava NIO TCPサーバーを構築しましたが、現在は4つのスレッドを使用しています。セレクタを使用する1つのServerRunnableスレッドと3つのワーカースレッドです。
プロセッサコアごとに1つのスレッドのみが必要であると以前に読んだように、これについていくつかの情報を探していました。これで終わりです。
しかし、それで最近不思議に思いました。もう少し調査した後、私は偶然出会いました このスレッド 。
承認された回答ユーザーのコメントで、Donal Fellowsは次のように指摘しています。
アプリケーションに割り当てられたプロセッサごとに最大で1つのCPUバウンドスレッドがあります。 IOバウンドスレッドは大きな問題ではなく(スレッドが消費するメモリ以外)、システムのCPUのサブセットのみを使用するようにアプリを制限できることを覚えておくことが重要です。結局のところ、それは(通常は)ユーザー/管理者のコンピューターであり、プログラマーのコンピューターではありません。
これを念頭に置いて、スレッドプール内のセレクタースレッドとワーカースレッドの数を安全に増やすことができると私は思っています。
私のサーバースレッドは入力を読み取り、データをJSONObjectsに処理してから、キューにプッシュします。次に、ワーカースレッドはJSONObjectsをキューから取得し、それらがどのタイプのオブジェクトであるかを確認して、データベースにプッシュします。したがって、そこで行われている計算作業はほとんどありません。より多くのServerRunnableスレッドとより多くのワーカースレッドを使用しているので、ここでスレッドの数を増やすのに十分ですか?たとえば、それぞれの量を2倍にしますか?
このようなことを考えるとき、私は何を考える必要がありますか?
処理能力は、コンピューターで最も希少なリソースです。私がこれを書いているとき、私が知っている最も高度なCPUには 18コアと約6グランドのコスト があります。真の並列処理が必要な場合は、スレッド数を18に制限します。 GUIまたは他の遅延に影響されないアプリケーションを作成している場合を除き、それ以上のものは過剰です。
シングルスレッドは、少なくとも1万の接続を処理できます。ここで、接続ごとに1つずつ、1万のスレッドが必要だと想像してみてください。
この記事CoralReactor を備えた高可用性サーバーについて見て、単一のスレッドがデマルチプレクサーとマルチプレクサーを介して何千もの接続を処理する方法を理解してください。
免責事項:私はCoralReactorの開発者の1人です。
マルチスレッドシステムの設計で重要なことの1つは、可能な限り多くのコアをビジー状態に保つように作業を分割する方法を理解することです。提案された設計では、2つのタイプのスレッドを使用します。これらのスレッドは、ほとんどがI/Oバウンドであり、それぞれに計算作業の一部を割り当てます。
I/Oにバインドされたスレッドを分離し、3種類のスレッドを使用して計算集約型のものを中央に配置することをお勧めします。
Input-入力を読み取り、それを入力キューに入れて、さらに入力を待つ状態に戻ります。私は、入力が単一のストリームであり、複数のリーダーを持つことは現実的ではないと想定しています。複数が機能する場合は、入力環境が提供するチャネルの数まで、これらのスレッドをさらに追加しても安全です。ここで重要な点は、入力をキューにできるだけ早くオフロードすると、処理中に遅延を追加することなく、スレッドがより多くの入力を読み取るか、I/Oバウンドになることです。これにより、取り込み率が最大になります。
Processing-入力キューからアイテムを取得し、JSONオブジェクトに変換し、タイプを決定し、正しいデータベースアクションをクックアップして出力キューに配置します。つまり、これは並列化可能でCPUを集中的に使用する作業のすべてです。
Output-出力キューからアイテムを取り出し、データベースに書き込みます。これらのスレッドはほとんど処理を行わず、入力スレッドと同様に、ほとんどの時間をI/Oが完了するまで待機します。
このモデルの利点は、キューの状態を使用してシステムのチューニング方法を決定できることです。
平均入力キューの長さが継続的に増加している場合は、入力負荷を処理するのに十分な処理スレッドがないことを意味します。解決策は、処理スレッドを追加するか、物理コアが不足している場合は、追加のマシンを入手することです。 (別のマシンが負荷の一部を拾う方が良いかもしれませんが、それは別の議論です。)
出力キューの増加は、データベースの書き込みを行う際にボトルネックがあることを意味します。通常は、データベースが並行して処理できる数の出力スレッドが必要です。これ以上、あなたはオーバーキューの問題をデータベースにオフロードしています。 (一部のデータベースは、他のデータベースよりも優れています。そのため、より多くの出力スレッドを使用するかどうかは、あなたしか決定できません。)