2016-05-23 9 views
3

Ich bin nicht sicher, warum OpenMP so viele Threads verwendet. Es scheint nicht mit der Microsoft-Implementierung verwandt zu sein, da ich auch die Intel-Bibliothek ausprobiert habe, die das gleiche Verhalten zeigt. Ich habe einige parallele Abschnitte in meinem Code, die compute-gebunden sind und nicht mehr Threads erstellen und verwenden sollten als ich Kerne habe. Aber was ich beobachtet habe, ist, dass OpenMP für n initiierende Threads n * Cores-Threads erstellt. Das sieht für mich wie ein großer Thread aus.OpenMP erstellt zu viele Threads

Wenn ich eine "kleine" 32-Bit-Anwendung auf einem Server ausführen, kann es fehlschlagen, da 1000 OpenMP-Threads 2 GB Adressraum bereits keinen Speicher für die Anwendung benötigen. Das sollte nicht passieren. Ich würde von einem State-of-the-Art-Thread-Pool erwarten, seine Threads wiederzuverwenden und nicht mehr verwendete Threads zu entfernen.

Ich habe versucht, omp_set_num_threads (8) verwenden, um die Thread-Pool-Größe auf 8 Kerne zu begrenzen, aber das scheint nur die Anzahl der Threads pro initiierenden Thread-Instanz zu begrenzen. Mache ich alles falsch oder soll OpenMP nicht so verwendet werden?

Auf meinem 8-Core-Maschine 5 gestartet Threads in meiner AsyncWorker-Klasse wird 38 Threads von OpenMP erstellt zuweisen. Ich würde erwarten, dass nur 8 Threads erstellt werden und diese sollten über alle 5 initiierenden Threads wiederverwendet werden.

enter image description here

#include <atomic> 
#include <thread> 
#include <omp.h> 
#include <chrono> 
#include <vector> 
#include <memory> 

class AsyncWorker { 
private: 
    std::vector<std::thread> threads; 

public: 
    AsyncWorker() 
    { 
    } 

    void start() // add one thread that starts an OpenMP parallel section 
    { 
     threads.push_back(std::thread(&AsyncWorker::threadFunc, this)); 
    } 

    ~AsyncWorker() 
    { 
     for (auto &t : threads) 
     { 
      t.join(); 
     } 
    } 

private: 
    void threadFunc() 
    { 
     std::atomic<int> counter; 

     auto start = std::chrono::high_resolution_clock::now(); 
     std::chrono::milliseconds durationInMs; 

     while (durationInMs.count() <5000l) 
     { 
     // each instance seems to get its own thread pool. 
     // Why? And how can I limit the threadpool to the number of cores and when will the threads be closed? 
#pragma omp parallel 
      { 
       counter++; 
       auto stop = std::chrono::high_resolution_clock::now(); 
       durationInMs = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start); 
      } 
     } 
    } 

}; 

int main() { 
    //omp_set_dynamic(0); 
    //omp_set_nested(0); 
    //omp_set_num_threads(8); 

    { 
     AsyncWorker foo; 

     foo.start(); // 1 
     foo.start(); // 2 
     foo.start(); // 3 
     foo.start(); // 4 
     foo.start(); // 5 

     system("pause"); 
    } 

    return 0; 
} 

Antwort

2

OpenMP ist nicht dazu gedacht, so verwendet zu werden. Mischen von OpenMP und anderen Threading-Methoden ist ein Rezept für ein Desaster, wenn es nicht sehr sorgfältig durchgeführt wird. Und selbst dann sind die Ergebnisse unvorhersehbar. Der OpenMP-Standard bleibt davon ab, eine solche Art von Interoperabilität zu definieren, und die Anbieter können diese nach Belieben bereitstellen (wenn sie es für richtig halten).

omp_set_num_threads(8) tut nicht, was Sie denken, dass es tut. Sie legt die Anzahl der Threads für parallele Bereiche fest, die vom aktuellen Thread gefunden werden, wenn keine Klausel num_threads() vorhanden ist. Außerdem hat omp_set_nested(0) keine Auswirkung, da Sie die parallelen Bereiche nicht aus OpenMP-Threads, sondern aus C++ 11-Threads starten. Über die Umgebungsvariable OMP_THREAD_LIMIT ist ein globales Limit für die Gesamtzahl der OpenMP-Threads möglich, aber das ist nur in OpenMP 3.0 und höher verfügbar und MSVC ist (für immer?) In der OpenMP 2.0-Ära festgefahren.

Handlungsmöglichkeiten sind:

  • Ihr eigenes Tasking für OpenMP 2 implementieren.0 unter Verwendung einer gemeinsamen Warteschlangenstruktur und OpenMP-Threads, die in einer Schleife Ausreihen Workitems Spin
  • ersetzen OpenMP mit Intel Threading Building Blocks - es ist Open-Source und unterstützt verschiedene Compiler auf Windows, Linux, OS X und Android
  • ersetzen OpenMP mit Microsofts PPL aus der Concurrency Runtime, die im Grunde eine nicht-portable Teilmenge von TBB
+0

Also unter welchen Umständen sind die Threads freigegeben? Bis jetzt sieht es nie aus. Die initiierenden Threads enden und der zugehörige Threadpool bleibt glücklich. Wie soll ich Ressourcen auf großen Kisten mit Hunderten von Kernen verwalten, wo dies den Speicherbedarf aufgrund tausender zugewiesener Thread-Stacks wirklich beeinträchtigt. Ist das Design von OpenMP wirklich so, dass es nur einen initiierenden Thread von parallelen Aktionen geben muss? Ich kann nicht glauben, dass C++ noch so weit zurückliegt, um echtes Multithreading zu unterstützen. –

+0

Ich denke, ich werde mit set OMP_THREAD_LIMIT =% NUMBER_OF_PROCESSORS% gehen, um die Anzahl der OpenMP-Threads zu begrenzen. Dies scheint eine vernünftige Wahl für CPU-gebundene parallele Operationen zu sein, die möglicherweise mehrere parallele Operationen gleichzeitig erzeugen können. –

+0

Übrigens ist es sicher, OMP_THREAD_LIMIT https://software.intel.com/en-us/node/522775 zu verwenden. Laut Intel könnte es manchmal Ihren Prozess zum Absturz bringen? "... Wenn dieses Limit erreicht ist und ein anderer nativer Betriebssystem-Thread auf OpenMP * API-Aufrufe oder -Konstrukte stößt, kann das Programm mit einer Fehlermeldung abbrechen ....". Bedeutet das, dass ich die Anzahl der OpenMP-Threads nicht sicher begrenzen kann? –

3

Die Anzahl der Threads verwendet OpenMP pro parallelen Abschnitt festgelegt ist, und man gleichzeitig das Laichen 5 parallele Abschnitte. Deshalb bekommst du 40 Threads.

Es scheint, dass Sie nach aufgabenbasierter Parallelität suchen. In OpenMP können Sie dies erreichen, indem Sie eine parallele Region starten und dann Aufgaben nach Bedarf erstellen. Von der Spitze von meinem Kopf Code für dieses Muster wie folgt geschrieben wird:

// Start parallel region 
#pragma omp parallel 
{ 
    // Only let a single thread create the tasks 
    #pragma omp single 
    { 
    for(int i = 0; i < 40; i++) 
    { 
     // Actually create the task that needs to be performed 
     #pragma omp task 
     { 
     heavy_work(); 
     } 
    } 
    } 
} 

Auf diese Weise würden Sie nur 8 Threads parallel arbeiten.

+0

bietet Leider unterstützt MS keine Aufgaben http://stackoverflow.com/questions/23545930/openmp-tasks-in-visual-studio. Ich kann auf die Intel lib (libiomp5md.lib) verlinken, aber ich muss in MSVC den OpenMP-Compiler-Support aktivieren, der sich dann mit "C3001: 'task': erwartet einen OpenMP-Direktivennamen" beschweren wird. Ansonsten müsste ich viel Code mit dem Intel C++ Compiler neu kompilieren. –

+2

@AloisKraus, Mischen von OpenMP und anderen Threading-Methoden wird nicht offiziell unterstützt. Es ist sozusagen eine Grauzone und in hohem Maße nicht portabel. Unter Windows verwenden Sie besser Intel Threading Building Blocks (es sollte mit neueren MSVCs gebaut werden) oder Microsoft's eigene [Concurrency Runtime] (https://msdn.microsoft.com/en-us/library/ee207192.aspx), die ist TBB sehr ähnlich. –

+0

Danke für die Warnung. Ich kenne Intel TBB aber diese werden aufgrund der hohen Lizenzkosten für den Intel Compiler selten genutzt. Ich würde gern bei einer von MSVC unterstützten Option bleiben, also muss ich in CCR schauen. –

Verwandte Themen