Producent-konsument korzystający z zadań OpenMP

Próbuję zaimplementować algorytm równoległy, używając zadań w OpenMP. Wzorzec programowania równoległego opiera się na idei producent-konsument, ale ponieważ proces konsumenta jest wolniejszy niż producent, chcę użyć kilku producentów i kilku konsumentów. Główną ideą jest stworzenie tylu wątków systemu operacyjnego co producentów, a następnie każdy z nich stworzy zadania do wykonania równolegle (przez konsumentów). Każdy producent będzie powiązany z proporcjonalną liczbą konsumentów (tj. NumCheckers / numSeekers). Używam algorytmu na serwerze Intel Dual-chip z 6 rdzeniami na chip. Rzecz w tym, że gdy używam tylko jednego producenta (poszukiwacza) i rosnącej liczby konsumentów (warcaby), wydajność spada bardzo szybko, ponieważ liczba konsumentów rośnie (patrz tabela poniżej), mimo że prawidłowa liczba rdzeni działa 100%. Z drugiej strony, jeśli zwiększę liczbę producentów, średni czas zmniejsza się lub przynajmniej utrzymuje się na stałym poziomie, nawet przy proporcjonalnej liczbie konsumentów. Wydaje mi się, że cała poprawa dokonywana jest przez podział wkładu między producentów, a zadania to tylko podsłuch. Ale znowu nie mam żadnego wyjaśnienia dla zachowania jednego producenta. Czy brakuje mi czegoś w logice OpenMP-Task? czy robię coś źle?

-------------------------------------------------------------------------
|   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    |
-------------------------------------------------------------------------

Główna część mojego kodu jest jak ugór:

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;
}

questionAnswers(2)

yourAnswerToTheQuestion