2012-04-04 10 views
43

Ich habe Probleme zu verstehen, das Konzept der blockierenden Kommunikation und nicht blockierende Kommunikation in MPI. Was sind die Unterschiede zwischen den beiden? Was sind die Vor- und Nachteile?MPI: Blockierung vs nicht blockierende

Danke!

Antwort

58

Die Blockierung der Kommunikation erfolgt über MPI_Send() und MPI_Recv(). Diese Funktionen kehren nicht zurück (d. H. Sie blockieren), bis die Kommunikation beendet ist. Etwas vereinfacht bedeutet dies, dass der an übergebene Puffer wiederverwendet werden kann, entweder weil MPI ihn irgendwo gespeichert hat oder weil er vom Ziel empfangen wurde. In ähnlicher Weise kehrt MPI_Recv() zurück, wenn der Empfangspuffer mit gültigen Daten gefüllt wurde.

Im Gegensatz dazu erfolgt die nicht blockierende Kommunikation mit MPI_Isend() und MPI_Irecv(). Diese Funktionen kehren sofort zurück (d. H. Sie blockieren nicht), selbst wenn die Kommunikation noch nicht beendet ist. Sie müssen MPI_Wait() oder MPI_Test() aufrufen, um zu sehen, ob die Kommunikation beendet ist.

Die Blockierungskommunikation wird verwendet, wenn sie ausreicht, da sie etwas einfacher zu verwenden ist. Nicht blockierende Kommunikation wird bei Bedarf verwendet, z. B. können Sie MPI_Isend() aufrufen, einige Berechnungen durchführen und dann MPI_Wait() tun. Dies ermöglicht eine Überlappung von Berechnungen und Kommunikation, was im Allgemeinen zu einer verbesserten Leistung führt.

Beachten Sie, dass die Sammelkommunikation (z. B. all-reduce) nur in ihrer blockierenden Version bis MPIv2 verfügbar ist. IIRC, MPIv3 führt nicht-blockierende kollektive Kommunikation ein.

Ein schneller Überblick über die Sendearten von MPI ist zu sehen here.

+1

so ein MPI_Send() ist das gleiche wie MPI_Isend() + MPI_Wait()? – lamba

+0

Ja, außer Overhead, können Sie sich MPI_Send() als MPI_Isend() gefolgt von einem MPI_Wait() vorstellen. – user1202136

+11

@ user1202136: Sie könnten erwähnen, dass "MPI_Send" abgeschlossen ist, wenn Sie den Puffer wiederverwenden können, unabhängig davon, ob der Empfänger die Daten empfangen hat (oder sogar, ob die Daten überhaupt gesendet wurden). –

8

In blockiert die Kommunikation verwenden, müssen Sie kümmern sich um Senden und Empfangen von Anrufen zum Beispiel Blick auf diesen Code

if(rank==0) 
{ 
    MPI_Send(x to process 1) 
    MPI_Recv(y from process 1) 
} 
if(rank==1) 
{ 
    MPI_Send(y to process 0); 
    MPI_Recv(x from process 0); 
} 

Was passiert in diesem Fall?

  1. Prozess 0 sendet x an Prozess 1 und blockiert, bis Prozess 1 x empfängt.
  2. Prozess 1 sendet y an Prozess 0 und blockiert, bis Prozess 0 y empfängt, aber
  3. Prozess 0 ist blockiert, sodass Prozess 1 für unendlich blockiert, bis beide Prozesse beendet sind.
+4

Früher dachte ich schon. Aber wenn ich MPI_Send auf meinem Computer verwende, finde ich das Problem innen komplizierter. Der obige Code funktioniert, da er die Nachricht in den Puffer verschieben könnte. Nur "MPI_Send" ist streng * blockiert *, da es zurückkehrt, bis das Ziel die Nachricht erhält. Die folgenden Links erklären, dass verschiedene Anbieter unterschiedliche Implementierungen wählen. http://www.mcs.anl.gov/research/projects/mpi/sendmode.html –

3

Es ist einfach.

Nicht blockierend bedeutet, dass die Berechnung und Übertragung von Daten gleichzeitig für einen einzelnen Prozess erfolgen kann.

Während Blocking bedeutet, hey Buddy, müssen Sie sicherstellen, dass Sie bereits Daten übertragen haben, dann zurück zum Abschluss des nächsten Befehls, was bedeutet, wenn eine Übertragung gefolgt von einer Berechnung erfolgt, muss die Berechnung nach dem Erfolg sein der Übertragung.

+0

es ist cool danke @Pab Peter –

3

Dieser Beitrag ist zwar ein bisschen alt, aber ich behaupte die angenommene Antwort. Die Aussage "Diese Funktionen kehren erst zurück, wenn die Kommunikation beendet ist" ist etwas irreführend, da die Blockierung der Kommunikation keinen Handshake in den Sende- und Empfangsoperationen garantiert.

Zuerst braucht man wissen, send hat vier Modi der Kommunikation: Standard Buffered, Synchron und Bereit und jede davon kann sein Blockierung und non-blocking

Im Gegensatz zu senden, hat empfangen nur einen Modus und kann blockieren sein oder nicht blockierend.

BLOCKIERENDE KOMMUNIKATION: Blockieren bedeutet nicht, dass die Nachricht an den Empfänger/Empfänger gesendet wurde. Es bedeutet lediglich, dass der (Sende- oder Empfangs-) Puffer zur Wiederverwendung verfügbar ist. Um den Puffer wieder zu verwenden, ist es ausreichend, die Information in einen anderen Speicherbereich zu kopieren, d. H. Die Bibliothek kann die Pufferdaten in einen eigenen Speicherplatz in der Bibliothek kopieren und dann, sagen wir zum Beispiel, MPI_Send zurückgeben.

Der MPI-Standard macht es sehr deutlich, die Nachrichtenpufferung von Sende- und Empfangsoperationen zu entkoppeln. Ein blockierender Versand kann abgeschlossen werden, sobald die Nachricht gepuffert wurde, obwohl kein passender Empfang gesendet wurde. In einigen Fällen kann die Nachrichtenpufferung jedoch teuer sein, und daher kann ein direktes Kopieren vom Sendepuffer zum Empfangspuffer effizient sein. Daher bietet MPI Standard vier verschiedene Sende-Modi, um dem Benutzer einige Freiheiten bei der Auswahl des geeigneten Sende-Modus für ihre Anwendung zu geben. Werfen wir einen Blick auf, was in jeder Art der Kommunikation geschieht:

1. Standard-Modus

Im Standard Modus ist es an der MPI-Bibliothek auf, ob die abgehende Nachricht puffern . In dem Fall, in dem die Bibliothek beschließt, die ausgehende Nachricht zu puffern, kann der Sendevorgang abgeschlossen werden, noch bevor der übereinstimmende Empfang aufgerufen wurde. In dem Fall, in dem die Bibliothek entscheidet, nicht zu puffern (aus Leistungsgründen oder aufgrund der Nichtverfügbarkeit von Pufferraum), wird der Sendevorgang nicht zurückkehren, bis ein übereinstimmender Empfang gesendet wurde und die Daten im Sendepuffer in den Empfangspuffer verschoben wurden.

So MPI_Send im Standard-Modus ist nicht lokale in dem Sinne, dass, ob ein Anpassungs werden kann im Standard-Modus senden begonnen erhalten gebucht wurde und dessen erfolgreichen Abschluss über das Auftreten einer Anpassungs erhalten abhängen kann (wegen zu der Tatsache, dass es implementierungsabhängig ist, ob die Nachricht zwischengespeichert wird oder nicht).

Die Syntax für Standard-Sende unter:

int MPI_Send(const void *buf, int count, MPI_Datatype datatype, 
      int dest, int tag, MPI_Comm comm) 

2. Buffered Mode

Wie im Standard-Modus kann die Sende in gepufferte Modus unabhängig von der Tatsache, dass eine passende gestartet werden Der Empfang wurde gesendet und der Sendevorgang kann abgeschlossen werden, bevor ein übereinstimmender Empfang gesendet wurde. Der Hauptunterschied ergibt sich jedoch aus der Tatsache, dass, wenn der Sendevorgang gestartet wird und kein übereinstimmender Empfang gesendet wird, die ausgehende Nachricht gepuffert werden muss. Beachten Sie, wenn der passende Empfang gepostet wird, kann der gepufferte Sender glücklich mit dem Prozessor zusammentreffen, der den Empfang gestartet hat, aber falls kein Empfang vorliegt, muss der gesendete Puffermodus die ausgehende Nachricht puffern, damit der Sendevorgang abgeschlossen werden kann.Ein gepufferter Send ist in seiner Gesamtheit local. Die Pufferzuweisung ist in diesem Fall benutzerdefiniert, und bei unzureichendem Pufferspeicher tritt ein Fehler auf.

Syntax für Puffer senden:

int MPI_Bsend(const void *buf, int count, MPI_Datatype datatype, 
      int dest, int tag, MPI_Comm comm) 

3. Synchronmodus

Im synchronen Sendemodus kann senden, ob eine passende gestartet erhalten gebucht wurde. Der Sendevorgang wird jedoch nur dann erfolgreich abgeschlossen, wenn ein übereinstimmender Empfang gesendet wurde und der Empfänger damit begonnen hat, die Nachricht zu empfangen, die vom synchronen Sendevorgang gesendet wurde. Die Beendigung des synchronen Sendens zeigt nicht nur an, dass der Puffer in dem Sendevorgang wiederverwendet werden kann, sondern auch die Tatsache, dass der empfangende Prozess begonnen hat, die Daten zu empfangen. Wenn sowohl Senden als auch Empfangen blockieren, wird die Kommunikation an jedem Ende vor dem Rendezvous des Kommunikationsprozessors nicht abgeschlossen.

Syntax für synchrone senden:

int MPI_Ssend(const void *buf, int count, MPI_Datatype datatype, int dest, 
       int tag, MPI_Comm comm) 

4. Bereitschaftsmodus

Im Gegensatz zu dem vorherigen drei-Modus kann ein Sende im Bereitschaftsmodus nur gestartet werden, wenn die passenden Empfang bereits gebucht wurde. Die Beendigung des Sendens zeigt nichts über den übereinstimmenden Empfang an und sagt lediglich, dass der Sendepuffer wiederverwendet werden kann. Ein Sendevorgang, der den Bereitschaftsmodus verwendet, hat die gleiche Semantik wie der Standardmodus oder ein Synchronmodus mit zusätzlichen Informationen über einen übereinstimmenden Empfang. Ein korrektes Programm mit einem Bereitschaftsmodus der Kommunikation kann durch einen synchronen Sendevorgang oder einen Standard-Sendevorgang ohne Auswirkung auf das Ergebnis ersetzt werden, abgesehen von der Leistungsdifferenz.

Syntax für Versand bereit:

int MPI_Rsend(const void *buf, int count, MPI_Datatype datatype, int dest, 
       int tag, MPI_Comm comm) 

Zum Glück entschied MPI Dinge easer für die Benutzer in Bezug zu halten von Empfangs- und gibt es nur eine erhalten in Blocking-Kommunikation: MPI_Recv und kann mit jedem verwendet werden, der vier oben beschriebenen Sendearten. Für MPI_Recv bedeutet die Blockierung, die nur dann zurückgegeben wird, wenn sie die Daten in ihrem Puffer enthält. Dies impliziert, dass Empfangen nur abgeschlossen werden kann, nachdem ein übereinstimmender Sendevorgang begonnen hat, aber nicht impliziert, ob es abgeschlossen werden kann, bevor der übereinstimmende Sendevorgang abgeschlossen ist.

Während solcher Blockierungsaufrufe passiert, dass die Berechnungen angehalten werden, bis der blockierte Puffer freigegeben wird. Dies führt normalerweise zu einer Verschwendung von Rechenressourcen, da Send/Recv üblicherweise Daten von einem Speicherort zu einem anderen Speicherort kopiert, während die Register in CPU im Leerlauf bleiben.

non-blocking COMMUNICATION: Für Nicht-Blocking Kommunikation, erstellt die Anwendung eine Anforderung zur Kommunikation für Sende- und/oder empfangen und einen Griff bekommt zurück und beendet dann. Das ist alles, was benötigt wird, um sicherzustellen, dass der Prozess ausgeführt wird. Dh die MPI-Bibliothek wird benachrichtigt, dass die Operation ausgeführt werden muss.

Auf der Senderseite ermöglicht dies eine überlappende Berechnung mit der Kommunikation.

Auf der Empfängerseite ermöglicht dies das Überlappen eines Teils des Kommunikationsaufwands, d. H. Kopieren der Nachricht direkt in den Adressraum der Empfangsseite in der Anwendung.