ここでは、「種類」の動的なフラットコンテナを持つスレッドプールがあるとします。このプールは、パフォーマンスを向上させるためにメモリがスタック上にあるため、最大容量がxです。最小限のコードで良いスレッドプールのキューサイズ
(私は特定に取得する必要はありません):
template <int32 QSIZE, int32 PSIZE> class ThreadPool
{
public:
ThreadPool()
{
for (int32 i = 0; PSIZE > i; ++i)
{
m_Workers.push(Thread(thread_main, m_Queue, m_Signal, m_IsRunning));
}
}
~ThreadPool()
{
//Wait and destroy all threads
}
void run(Task task)
{
m_Queue.push(task);
m_Signal.wake_all();
}
private:
FlatVector<Thread, PSIZE> m_Workers; //PSIZE --> max capacity
FlatQueue<Task, QSIZE> m_Queue; //QSIZE --> max capacity
ConditionVariable m_Signal;
AtomicBool m_IsRunning;
};
class Task
は、バインドされたパラメータと意味動かすとインプレース関数の実装です。
FlatVector
は、メモリがスタック上にあり、最大容量がPSIZE
(プールサイズ)のベクタです。
FlatQueue
は、基本的にQSIZE
(キューサイズ)の容量を持つキューと同じ構築物である
一つTask
は、512ビットの最大サイズを有します。
最悪の場合、スレッドプールのタスクキューがどのくらい大きくなるべきでしょうか? (可能であれば、与えられた例を考慮して、可能ならば通常のスレッドプールの推測も問題ありません)
ほとんどの場合、私のプールは8つのスレッドで実行されています。プールを使用すると、スレッド数が増えるというメリットがあります。
タスクをタスクバンドルにパッケージ化する方が良いでしょうか(この例では512ビットを超えない限り)、計算をスキップするだけでいいですか?このフレームにもう配置できず、次のフレームでそれらを計算することはできませんか?物理計算は2フレーム分計算されます。
私はキューサイズを64から128の間で選択していますが、パフォーマンスはそれほど優れていませんが、実際にはプール内の128のタスクが同時に感じられます。この量のメモリを無駄にしたくありません。
時々私は私が高負荷でプールを設定した場合、同時にプール内の64個のタスクの制限を超えています。 (私は最初の場所でのプールのサイズを大きくすることを決めた理由です。)
私のプールに、単一の512ビットのタスク(最悪の場合)を追加すると1,02と1,3電子パワー(-7)秒の間に何かを取ります私のシステムで
「通常の」スレッドプールとヒープ割り当てと移動セマンティクスを持つ「通常の」関数バインディングでは、1.8〜2.3 eのパワー(-5)秒の間に何かが起こります。この場合スタックされます。
独自のスレッドプールクラスを作成することは、独自の文字列クラスを作成するのとよく似ています。おそらくあなたの人生で少なくとも一度はこれを行うことが大切ですが、他のプログラマと何をしたのかを比較することと同じくらい重要です。 *その*だけが洞察を提供します。そうすることで、その最適値はコードが実行されている特定のマシンに依存するランタイムの詳細なので、PSIZEがなくなります。そして、あなたは値を前もって推測し、その限界を超えて対処するためのまともな方法がないので、QSIZEも排除する可能性が非常に高いでしょう。それは重要です。 –
公平なポイント、私はプール(通常)はCPUコアのサイズを持つべきであることを知っています。後で少なくともスレッド数は実行時にgetCoreCount()関数で置き換えられます(これはあなたが正しいところです)。それにもかかわらず、スタックコンテナの性能上の利点は強いため、QSIZEを持つスタックコンテナはそのままになります。実際には、私はあまり好きではない方法でオーバーフローを処理しています。キューがいっぱいであれば、メインスレッドで実行します。それは私が将来避けたいものです。そのために、より並列的に実行されるより良いソリューションを探しています。 – Mango