Producer-Consumer mit OpenMP-Tasks

Ich versuche, einen parallelen Algorithmus mithilfe von Aufgaben in OpenMP zu implementieren. Das Muster der parallelen Programmierung basiert auf der Idee von Produzent und Konsument, aber da der Konsumentenprozess langsamer als der Produzent ist, möchte ich einige Produzenten und mehrere Konsumenten verwenden. Die Hauptidee besteht darin, so viele Betriebssystem-Threads wie Produzenten zu erstellen, und jede dieser Threads erstellt Aufgaben, die (von den Konsumenten) parallel ausgeführt werden. Jeder Produzent wird einer proportionalen Anzahl von Konsumenten zugeordnet (d. H. NumCheckers / numSeekers). Ich verwende den Algorithmus auf einem Intel Dual-Chip-Server mit 6 Kernen pro Chip. Die Sache ist, dass, wenn ich nur einen Produzenten (Sucher) und eine zunehmende Anzahl von Konsumenten (Prüfer) benutze, die Leistung sehr schnell abnimmt, wenn die Anzahl der Konsumenten zunimmt (siehe Tabelle unten), obwohl die richtige Anzahl von Kernen an einem arbeitet 100%. Wenn ich dagegen die Zahl der Erzeuger erhöhe, sinkt die durchschnittliche Zeit, oder sie bleibt zumindest stabil, selbst bei einer proportionalen Anzahl von Verbrauchern. Mir scheint, dass die ganze Verbesserung durch die Aufteilung des Inputs auf die Produzenten zustande kommt und die Aufgaben nur lästig sind. Aber auch hier habe ich keine Erklärung für das Verhalten mit einem Produzenten. Vermisse ich etwas in der OpenMP-Task-Logik? Mache ich etwas falsch?

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

Der Hauptteil meines Codes ist wie folgt:

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

Antworten auf die Frage(2)

Ihre Antwort auf die Frage