【问题标题】:Understanding Put/Get in mpi4py了解 mpi4py 中的 Put/Get
【发布时间】:2020-02-22 18:46:33
【问题描述】:

我正在学习如何在 mpi4py 中使用单向通信。为了测试我的理解,我想出了这个人为的例子:

import mpi4py.MPI as mpi
import numpy as np
import time

def main():
    rank = mpi.COMM_WORLD.Get_rank()
    n_proc = mpi.COMM_WORLD.Get_size()

    assert(n_proc == 2)

    buff = np.zeros(10, dtype='d')
    win = mpi.Win.Create(buff, 1, mpi.INFO_NULL, mpi.COMM_WORLD)

    if (rank == 0):
        win.Lock(1)
        win.Put([buff, mpi.DOUBLE], 1)
        win.Unlock(1)

        buff[-1] = 9
        time.sleep(30)

        win.Lock(1)
        win.Put([buff, mpi.DOUBLE], 1)
        win.Unlock(1)

    else:
        holder = np.zeros(10)
        failures = 0
        while (holder[-1] != 9):
            failures += 1
            win.Lock(0)
            win.Get([holder, mpi.DOUBLE], 0)
            win.Unlock(0)
        print('Took', failures, 'dials')

if __name__=='__main__':
    main()

我希望它按如下方式工作:rank 0 将等待 30 秒,然后将包含 [0, 0, ..., 0, 9] 的 ndarray 放入共享内存中。同时,rank 1 将不断检查 rank 0 是否更新了它的共享内存——一旦更新,它将打印出它看到的内容。具体来说,我希望 rank 1 会在 30 秒等待期间多次执行其 while 循环,而 rank 0 空闲。但是,当我使用 mpirun -n 2 python mwe.py 运行此代码时,我始终得到以下输出:

Took 2 dials

表示对Get的调用只发生了两次。

具体问题:为什么排名 1 的 Get 只有两次调用?

更模糊的问题:我在这个 MWE 中是否犯了明显的错误?一般来说,我对 mpi4py/MPI 还是很陌生。

【问题讨论】:

    标签: python-3.x parallel-processing mpi mpi4py


    【解决方案1】:

    正如你所说的那样,您正在创建一个共享内存窗口。该窗口允许通信器中的其他 MPI 进程直接访问存储您的buff 的确切内存。当您更改buff[-1] = 9 时,这当然会存储在所述内存中,并且窗口会立即受到影响。因此,对本地进程(从 rank 0 到 rank 0)的显式调用 Put 是不必要的,Put 仅用于将数据放置在 remote 内存窗口中。其他 MPI 进程可以在排名 0 甚至开始其 30 秒睡眠操作之前从窗口中读取您更改的 buff 变量。

    不幸的是,您看到“Took 2 dials”的原因是因为 rank 0 和 1 可能同时执行他们的第一次锁定和解锁,然后 rank 0 执行buff[-1] = 9,然后循环在 rank 1 上重复,它读取更新的缓冲区并在 2 次迭代后退出。

    PS:为了测试,在buff[-1] = 9之前放置一个1s sleep

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-04
      相关资源
      最近更新 更多