上記のように、この関数に入るたびにスレッドを開始しないでください。さらに、ジョブ作成のオーバーヘッドが十分に償却されるように、内部関数の 1 つの操作よりも大きな「ジョブ」粒度を使用してください。元のルーチンを次のように説明します。
void OuterFunction( Thingy inputData[N] )
{
for ( int i = 0 ; i < N ; ++i )
InnerFunction( inputData[i] );
}
問題を解決するには (ジョブ キュー システムが存在すると仮定します):
void JobFunc( Thingy inputData[], int start, int stop )
{
for ( int i = start ; i < stop ; ++i )
InnerFunction( inputData[i] );
}
void OuterFunction( Thingy inputData[N], int numCores )
{
int perCore = N / numCores; // assuming N%numCores=0
// (omitting edge case for clarity)
for ( int c = 0 ; c < numCores ; ++c )
QueueJob( JobFunc, inputData, c * perCore, (c + 1) * perCore );
}
元の質問で言うように、入力データが完全に独立している限り、ロックする必要はありません。同期は、スレッド間に依存関係があり、ここでは依存関係がない場合にのみ必要です。
また、このレベルのパフォーマンスでは、マイクロ最適化が適切になり始めます。最も重要なのは、キャッシュの局所性です。プリフェッチは、驚くほど長い道のりを歩むことができます。
次に、SIMD をベクトル化して、1 つのレジスターで 4 つの入力ポイントを同時に実行できる可能性を検討します。4 つのコアと 4 幅の SIMD を使用すると、理論的には 16 倍のスピードアップを得ることができますが、これは、InnerFunction が行っている作業のほとんどが固定の数学関数であると想定しています。