OpenMP 内のタスクを使用して並列アルゴリズムを実装しようとしています。並列プログラミング パターンはプロデューサー/コンシューマーの考え方に基づいていますが、コンシューマー プロセスはプロデューサーよりも遅いため、少数のプロデューサーと複数のコンシューマーを使用したいと考えています。主なアイデアは、プロデューサーと同じ数の OS スレッドを作成し、これらのそれぞれが (コンシューマーによって) 並行して実行されるタスクを作成することです。すべてのプロデューサは、比例した数のコンシューマ (つまり、numCheckers/numSeekers) に関連付けられます。チップあたり 6 コアのインテル デュアルチップ サーバーでアルゴリズムを実行しています。問題は、1 つのプロデューサー (シーカー) と増加する数のコンシューマー (チェッカー) のみを使用すると、正しい数のコアが動作しているにもかかわらず、コンシューマーの数が増えるにつれてパフォーマンスが非常に速く低下することです (下の表を参照)。 100%。一方で、プロデューサーの数を増やすと、コンシューマーの数が比例していても、平均時間が減少するか、少なくとも安定したままになります。すべての改善は生産者間の入力の分割によって行われ、タスクはバグであると私には思えます。しかし、繰り返しになりますが、あるプロデューサーの振る舞いについては説明がありません。OpenMP-Task ロジックで何か不足していますか? 私は何か間違ったことをしていますか?
-------------------------------------------------------------------------
| producers | consumers | time |
-------------------------------------------------------------------------
| 1 | 1 | 0.642935 |
| 1 | 2 | 3.004023 |
| 1 | 3 | 5.332524 |
| 1 | 4 | 7.222009 |
| 1 | 5 | 9.472093 |
| 1 | 6 | 10.372389 |
| 1 | 7 | 12.671839 |
| 1 | 8 | 14.631013 |
| 1 | 9 | 14.500603 |
| 1 | 10 | 18.034931 |
| 1 | 11 | 17.835978 |
-------------------------------------------------------------------------
| 2 | 2 | 0.357881 |
| 2 | 4 | 0.361383 |
| 2 | 6 | 0.362556 |
| 2 | 8 | 0.359722 |
| 2 | 10 | 0.358816 |
-------------------------------------------------------------------------
私のコードの主要なセクションは次のとおりです。
int main( int argc, char** argv) {
// ... process the input (read from file, etc...)
const char *buffer_start[numSeekers];
int buffer_len[numSeekers];
//populate these arrays dividing the input
//I need to do this because I need to overlap the buffers for
//correctness, so I simple parallel-for it's not enough
//Here is where I create the producers
int num = 0;
#pragma omp parallel for num_threads(numSeekers) reduction(+:num)
for (int i = 0; i < numSeekers; i++) {
num += seek(buffer_start[i], buffer_len[i]);
}
return (int*)num;
}
int seek(const char* buffer, int n){
int num = 0;
//asign the same number of consumers for each producer
#pragma omp parallel num_threads(numCheckers/numSeekers) shared(num)
{
//only one time for every producer
#pragma omp single
{
for(int pos = 0; pos < n; pos += STEP){
if (condition(buffer[pos])){
#pragma omp task shared(num)
{
//check() is a sequential function
num += check(buffer[pos]);
}
}
}
#pragma omp taskwait
}
return num;
}