構成によって生成されたツリーがあります。
ツリーの各葉は、実行時間の長いタスク(DBクエリ、ファイルからの読み取りなど)であり、結果のみを含むミラー化されたツリーに保存したい結果が得られます。非葉ノードには計算がありません(ツリーの構造と高さは構成によって指定されます)。
現在のバージョンのソフトウェアでは、ノードがリーフであるかどうかに関係なく(つまり、複数のノードに並列にアクセスして)、非リーフノードごとに固定スレッドプールエグゼキューター(Java)を作成し、スレッドプール内でビジットを実行します。 。次に、非リーフノードごとに、訪問は自身の子が終了するのを待ちます。疑似コードで書くことは少し似ています(結果の保存部分をスキップします)
void visit(NonLeafNode node){
pool = new FixedThreadPool(node.poolSize) //this number is part of the configuration of the node;
for (child in children){
pool.submit(visit(child))
}
while(pool is not empty){
wait()
}
}
void visit(LeafNode node){
task()
}
私はそれがアプローチには2つの欠陥があると思います:
並列でツリーを訪問する実際の必要はありません(サイズは10から100の間ですが、それが1000だったとしても...)
構成に基づいて動的な数のスレッドとエグゼキューターを作成していますが、その数はおそらく必要以上の数です。
私の個人的な解決策は、1人のエグゼキューターがいて、すべての葉を集めて、それらをすべて一緒に(最初の呼び出しでのみ再帰的にではなく)送信することです。
void visit(Root node){
pool = new FixedThreadPool(poolSize) //this is global configuration
tasks = new List<Tasks>()
for(child in children){
visit(child, tasks)
}
for(task in tasks){
pool.submit(task)
}
wait
}
void visit(NonLeaf node, tasks){
for(child in children){
visit(child, tasks)
}
}
void visit(Leaf node, tasks){
tasks.add(() -> task()) // only using the reference of the task
}
私はそのコメントを得た
このようにして、ノードあたりのスレッド数を設定することはできません
スレッド数が制限されているため、デッドロックが発生する可能性があります。
それで、この特定のケースでは、一般的には、Nプールまたは1つの固定プールの方が優れていますか?
スレッドプールを実行する2つの基本的な理由があります。
進行中のスレッドの作成 コストが高い 。プールを使用すると、それらを1回だけ作成し、必要に応じて再利用してオーバーヘッドを節約できます。
最適なスレッド数は、主に ハードウェアの特性 によって駆動され、多くの場合、CPUコア数の倍数として計算されます。これには理由があります。ハードウェアが20スレッドをサポートする場合、必要と考える数に関係なく、20スレッドをサポートします。さらに追加すると、実際には逆効果になります。 (ロジックに必要なものに基づいて、tasksの動的な数を割り当てることはできるかもしれませんが、それらのタスクが実行されるスレッドの数は比較的固定されているはずです、それらを最適な数を超えて増やす意味がないからです)。
私がよく知っているアーキテクチャには、アプリケーションの起動時に1つまたは2つのスレッドプールを作成し、必要に応じてそのプールのスレッドを再利用することが含まれます。
あなたが私に示しているアーキテクチャは、プールが必要に応じて動的に割り当てられるため、一般的な慣習に反しているようであり、アプリケーションの動作に異常がある場合にのみ意味があります。ある?