=============================== Nichtblockierende Kommunikation =============================== `MPI_Send` blockiert den Aufrufer bis die Nachricht versandt ist und der angegebene Speicherbereich wiederverwendet werden kann. `MPI_Recv` blockiert den Aufrufer bis zum Eingang einer passenden Nachricht. Das Blockieren ist ein Nachteil, wenn mehr als eine Nachricht zu empfangen oder zu versenden ist und sich somit Latenzzeiten unnötig addieren. Hinzu kommt, dass bei den blockierenden Operationen eine Parallelisierung der Kommunikation und des Rechnens nicht möglich ist ohne Threads zu verwenden. Grundsätzlich stehen alle Versand- und Empfangs-Operationen bei MPI auch in einer asynchronen Variante zur Verfügung. Statt `MPI_Send` und `MPI_Recv` können `MPI_Isend` und `MPI_Irecv` verwendet werden. Das `I` steht hier für _immediate_, d.h. die Aufrufe blockieren nicht und kehren sofort zurück. Sie dienen nur der Initiierung der Kommunikation. Später können wir sehen, ob sie abgeschlossen sind bzw. darauf warten, dass sie fertig werden. Hier sind die Signaturen von `MPI_Isend` und `MPI_Irecv`: ---- CODE (type=cpp) ---------------------------------------------------------- int MPI_Isend(const void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request* request); int MPI_Irecv(void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request* request); ------------------------------------------------------------------------------- Die Parameter sind ähnlich wie bei `MPI_Send` und `MPI_Recv`. Es kommt hier jeweils ein Zeiger auf ein `MPI_Request`-Objekt hinzu, auf der Empfangsseite entfällt der Zeiger auf das `MPI_Status`-Objekt. Über die `MPI_Request`-Objekte ist nun eine Überprüfung des aktuellen Status oder ein Warten möglich: ---- CODE (type=cpp) ---------------------------------------------------------- int MPI_Wait(MPI_Request* request, MPI_Status* status); int MPI_Test(MPI_Request* request, int* flag, MPI_Status* status); ------------------------------------------------------------------------------- `MPI_Wait` blockiert, bis die entsprechende Operation abgeschlossen ist. Der Status, der insbesondere auf der Empfangsseite relevant ist, wird in dem `MPI_Status`-Objekt abgelegt. Bei `MPI_Test` wird `*flag` auf `true` gesetzt, falls die Operation bereits abgeschlossen ist. In diesem Fall wird `*status` gesetzt. Ansonsten ist `*flag` `false` und `*status` bleibt undefiniert. Aufgabe ======= Ersetzen Sie in Ihrer Lösung zum Jacobi-Verfahren (oder in der unten folgenden Vorlage) die blockierende Kommunikation zwischen den Jacobi-Iterationen durch nicht-blockierende. Sollten Sie die Vorlage verwenden, wäre nur die Funktion `exchange_with_neighbors` anzupassen. Vergleichen Sie die Ausführungszeiten mit und ohne blockierende Kommunikation. Vorlage ======= :import:session22/jacobi.cpp :navigate: up -> doc:index back -> doc:session22/page04 next -> doc:session22/page06