同 comm.gather
一样, comm.reduce
接收一个数组,每一个元素是一个进程的输入,然后返回一个数组,每一个元素是进程的输出,返回给
root 进程。输出的元素中包含了简化的结果。
在 mpi4py
中,我们将简化操作定义如下: :
comm.Reduce(sendbuf, recvbuf, rank_of_root_process, op = type_of_reduction_operation)
这里需要注意的是,这里有个参数 op
和 comm.gather
不同,它代表你想应用在数据上的操作, mpi4py
模块代表定义了一系列的简化操作,其中一些如下:
MPI.MAX
: 返回最大的元素MPI.MIN
: 返回最小的元素MPI.SUM
: 对所有元素相加MPI.PROD
: 对所有元素相乘MPI.LAND
: 对所有元素进行逻辑操作MPI.MAXLOC
: 返回最大值,以及拥有它的进程MPI.MINLOC
: 返回最小值,以及拥有它的进程现在,我们用 MPI.SUM
实验一下对结果进行相加的操作。每一个进程维护一个大小为 3 的数组,我们用
numpy
来操作这些数组: :
import numpy
import numpy as np
from mpi4py import MPI
comm = MPI.COMM_WORLD
size = comm.size
rank = comm.rank
array_size = 3
recvdata = numpy.zeros(array_size, dtype=numpy.int)
senddata = (rank+1)*numpy.arange(size,dtype=numpy.int)
print("process %s sending %s " % (rank , senddata))
comm.Reduce(senddata, recvdata, root=0, op=MPI.SUM)
print('on task', rank, 'after Reduce: data = ', recvdata)
我们用通讯组进程数为 3 来运行,等于维护的数组的大小。输出的结果如下: :
C:\>mpiexec -n 3 python reduction2.py
process 2 sending [0 3 6]
on task 2 after Reduce: data = [0 0 0]
process 1 sending [0 2 4]
on task 1 after Reduce: data = [0 0 0]
process 0 sending [0 1 2]
on task 0 after Reduce: data = [ 0 6 12]
为了演示相加简化操作,我们使用 comm.Reduce
语句,并将含有 recvbuf
的
rank 设置为 0, recvdata
代表了最后的计算结果: :
comm.Reduce(senddata, recvdata, root=0, op=MPI.SUM)
我们的 op = MPI.SUM
选项,将在所有的列上面应用求和操作。下图表示了这个步骤:
操作的过程如下:
简化操作将每个 task 的第 i 个元素相加,然后放回到 P0 进程的第 i 个元素中。在接收操作中, P0 收到数据 [0 6 12]。
(译注:"简化"翻译的可能不太合适)