MPI

Oft erfordert ein paralleler Algorithmus das Verschieben von Daten zwischen den Engines. Eine Möglichkeit besteht darin, Push und Pull über die DirectView. Dies ist jedoch langsam, da alle Daten über den Controller zum Client und dann wieder zurück zum endgültigen Ziel gelangen müssen.

Eine viel bessere Möglichkeit ist die Verwendung des Message Passing Interface (MPI). Die Parallel-Computing-Architektur von IPython wurde von Grund auf für die Integration mit MPI entwickelt. Dieses Notebook gibt eine kurze Einführung in die Verwendung von MPI mit IPython.

Anforderungen

  • Eine Standard-MPI-Implementierung wie OpenMPI oder MPICH.

    Für Debian/Ubuntu können diese installiert werden mit

    $ sudo apt install openmpi-bin
    

    oder

    $ sudo apt install mpich
    

    Alternativ können OpenMPI oder MPICH auch mit Spack installiert werden: die Pakete sind openmpi oder mpich.

  • mpi4py

Starten der Engines bei aktiviertem MPI

Automatisches Starten mit mpiexec und ipcluster

Dies kann z.B. erfolgen mit

$ pipenv run ipcluster start -n 4 --profile=mpi

Hierfür muss jedoch zuvor ein entsprechendes Profil angelegt werden; siehe hierfür Konfiguration.

Automatisches Starten mit PBS und ipcluster

Der ipcluster-Befehl bietet auch eine Integration in PBS. Weitere Informationen hierzu erhaltet ihr in Starting IPython Parallel on a traditional cluster.

Beispiel

Die folgende Notebook-Zelle ruft psum.py mit folgendem Inhalt auf:

import numpy as np

from mpi4py import MPI


def psum(a):
    locsum = np.sum(a)
    rcvBuf = np.array(0.0, "d")
    MPI.COMM_WORLD.Allreduce(
        [locsum, MPI.DOUBLE], [rcvBuf, MPI.DOUBLE], op=MPI.SUM
    )
    return rcvBuf
[1]:
import ipyparallel as ipp


c = ipp.Client(profile="mpi")
view = c[:]
view.activate()
view.run("psum.py")
view.scatter("a", np.arange(16, dtype="float"))
view["a"]
[1]:
[array([0., 1., 2., 3.]),
 array([4., 5., 6., 7.]),
 array([ 8.,  9., 10., 11.]),
 array([12., 13., 14., 15.])]
[2]:
%px totalsum = psum(a)
[2]:
Parallel execution on engines: [0,1,2,3]
[3]:
view["totalsum"]
[3]:
[120.0, 120.0, 120.0, 120.0]