3. 多进程并行 (MPI)#

在终端使用 mpiexec -n <np> 运行 python 文件即可:

mpiexec -n 2 python myscript.py

3.1. Run code parallelly in jupyter#

我们使用 ipyparallel 介绍并行程序的一些内容, 需要先安装 ipyparallel

3.1.1. Install ipyparallel#

  1. Install ipyparallel in firedrake env:

    pip install ipyparallel
    
  2. create profile mpi

    ipython profile create --parallel --profile=mpi
    

    Your will see the following output

    [ProfileCreate] Generating default config file: 
        PosixPath('/home/<your-user-name>/.ipython/profile_mpi/ipython_config.py')
    [ProfileCreate] Generating default config file: 
        PosixPath('/home/<your-user-name>/.ipython/profile_mpi/ipython_kernel_config.py')
    [ProfileCreate] Generating default config file: 
        PosixPath('/home/<your-user-name>/.ipython/profile_mpi/ipcontroller_config.py')
    [ProfileCreate] Generating default config file: 
        PosixPath('/home/<your-user-name>/.ipython/profile_mpi/ipengine_config.py')
    [ProfileCreate] Generating default config file: 
        PosixPath('/home/<your-user-name>/.ipython/profile_mpi/ipcluster_config.py')
    
  3. Edit file .ipython/profile_mpi/ipengine_config.py. Add the following code at the begining of the file:

    from firedrake import *
    from firedrake.petsc import PETSc
    
  4. Set the default engines to mpi in file .ipython/profile_mpi/ipcluster_config.py. You can search engine_launcher_class in the file, and the result file should looks like this:

    #    - sshproxy: ipyparallel.cluster.launcher.SSHProxyEngineSetLauncher
    #    - winhpc: ipyparallel.cluster.launcher.WindowsHPCEngineSetLauncher
    #  Default: 'ipyparallel.cluster.launcher.LocalEngineSetLauncher'
    c.Cluster.engine_launcher_class = 'mpi'
    
  5. Test:

    import ipyparallel as ipp
    import os
    
    cluster = ipp.Cluster(profile="mpi", n=2)
    client = cluster.start_and_connect_sync()
    

    The output should looks like

    Starting 2 engines with <class 'ipyparallel.cluster.launcher.MPIEngineSetLauncher'>
    
    %%px --block
    from firedrake import *
    from firedrake.petsc import PETSc
    from mpi4py import MPI
    
    mesh = RectangleMesh(8, 8, 1, 1)
    PETSc.Sys.syncPrint(mesh.comm.rank, mesh.comm.size)
    PETSc.Sys.syncFlush()
    

    The output should looks like:

    [stdout:0] 0 2
    1 2
    

3.1.2. Example#

import ipyparallel as ipp
import os

cluster = ipp.Cluster(profile="mpi", n=2)
client = cluster.start_and_connect_sync()
Starting 2 engines with <class 'ipyparallel.cluster.launcher.MPIEngineSetLauncher'>
%%px --block
from firedrake import *
from firedrake.petsc import PETSc
from mpi4py import MPI

mesh = RectangleMesh(8, 8, 1, 1)
PETSc.Sys.syncPrint(mesh.comm.rank, mesh.comm.size)
PETSc.Sys.syncFlush()
[stdout:0] 0 2
1 2
%%px --block

PETSc.Sys.syncPrint(COMM_WORLD.rank, COMM_WORLD.size)
PETSc.Sys.syncFlush()
[stdout:0] 0 2
1 2

有些时候需要在某个进程上, 做指定的操作或运算, 如只在第0个进程上画图

if COMM_WORLD.rank == 0:
    plot(...)

3.2. 并行输出#

py/intro_utils.py

%%px --block 
from firedrake import *
from firedrake.petsc import PETSc
from mpi4py import MPI

PETSc.Sys.Print('This is first line (from rank 0)')
[stdout:0] This is first line (from rank 0)
%%px --block 
PETSc.Sys.syncPrint('This is second line (from all rank)')
PETSc.Sys.syncFlush()
[stdout:0] This is second line (from all rank)
This is second line (from all rank)
%%px --block
print('This msg from all rank')
[stdout:0] This msg from all rank
[stdout:1] This msg from all rank