Общая память в mpi4py

Я использую скрипт MPI (mpi4py) (на одном узле), который работает с очень большим объектом. Для того, чтобы все процессы имели доступ к объекту, я раздаю его через comm.bcast(). Это копирует объект во все процессы и потребляет много памяти, особенно в процессе копирования. Поэтому я хотел бы поделиться чем-то вроде указателя вместо самого объекта. Я нашел некоторые функции в memoryview полезными для ускорения работы с объектом внутри процесса. Также реальный адрес памяти объекта доступен через строковое представление объекта memoryview и может быть распределен следующим образом:

from mpi4py import MPI

comm = MPI.COMM_WORLD
rank = comm.Get_rank()

if rank:
    content_pointer = comm.bcast(root = 0)
    print(rank, content_pointer)
else:
    content = ''.join(['a' for i in range(100000000)]).encode()
    mv = memoryview(content)
    print(mv)
    comm.bcast(str(mv).split()[-1][: -1], root = 0)

Это печатает:

<memory at 0x7f362a405048>
1 0x7f362a405048
2 0x7f362a405048
...

Вот почему я считаю, что должен быть способ воссоздать объект в другом процессе. Однако я не могу найти подсказку в документации о том, как это сделать.

Короче говоря, мой вопрос: Возможно ли совместно использовать объект между процессами на одном узле в mpi4py?


person Roman    schedule 09.09.2015    source источник
comment
не могли бы вы принять новый ответ MPI 3.0 JobJob как правильный?   -  person Robin De Schepper    schedule 21.01.2021


Ответы (2)


Я мало что знаю о mpi4py, но с точки зрения MPI это невозможно. MPI расшифровывается как Message Passing Interface, что означает именно это: передавать сообщения между процессами. Для напоминают что-то вроде глобально доступной памяти, но в остальном память процесса недоступна для других процессов.

Если вам нужно полагаться на большой блок общей памяти, вам нужно использовать что-то вроде OpenMP или потоков, которые вы вполне можете использовать на одном узле. Гибридное распараллеливание с MPI и некоторым распараллеливанием разделяемой памяти позволит вам иметь один блок разделяемой памяти на узел, но при этом останется возможность использовать множество узлов.

person haraldkl    schedule 09.09.2015
comment
Этот ответ неверен в свете общей памяти MPI 3.0 (software.intel.com/en-us/articles/) - person Ben Thompson; 11.08.2017
comment
@BenThompson Хорошо, вы хотите, чтобы я удалил его или изменил ответ? У меня нет опыта работы с этой новой функцией... - person haraldkl; 11.08.2017

Вот простой пример использования общей памяти с использованием MPI, слегка измененный из https://groups.google.com/d/msg/mpi4py/Fme1n9niNwQ/lk3VJ54WAQAJ

Вы можете запустить его с помощью: mpirun -n 2 python3 shared_memory_test.py (при условии, что вы сохранили его как shared_memory_test.py)

from mpi4py import MPI 
import numpy as np 

comm = MPI.COMM_WORLD 

# create a shared array of size 1000 elements of type double
size = 1000 
itemsize = MPI.DOUBLE.Get_size() 
if comm.Get_rank() == 0: 
    nbytes = size * itemsize 
else: 
    nbytes = 0

# on rank 0, create the shared block
# on rank 1 get a handle to it (known as a window in MPI speak)
win = MPI.Win.Allocate_shared(nbytes, itemsize, comm=comm) 

# create a numpy array whose data points to the shared mem
buf, itemsize = win.Shared_query(0) 
assert itemsize == MPI.DOUBLE.Get_size() 
ary = np.ndarray(buffer=buf, dtype='d', shape=(size,)) 

# in process rank 1:
# write the numbers 0.0,1.0,..,4.0 to the first 5 elements of the array
if comm.rank == 1: 
    ary[:5] = np.arange(5)

# wait in process rank 0 until process 1 has written to the array
comm.Barrier() 

# check that the array is actually shared and process 0 can see
# the changes made in the array by process 1
if comm.rank == 0: 
    print(ary[:10])

Должен выводить это (напечатано из ранга процесса 0):

[0. 1. 2. 3. 4. 0. 0. 0. 0. 0.]
person JobJob    schedule 07.02.2018
comment
Как насчет многомерного массива, скажем, np.zeros((50, 50, 50))? - person Zézouille; 18.06.2020
comment
@Zézouille для многомерного массива это похоже, вы просто сделали бы (приблизительно) следующие изменения: size = 1000 на shape = (50,50,50), size = np.prod(shape), и эта строка станет ary = np.ndarray(buffer=buf, dtype='d', shape=shape) # instead of shape=(size,), и чтобы запустить этот конкретный пример, вы также хотели бы изменить ary[:5] = np.arange(5) на ary[:5, 1, 1] = np.arange(5) и print(ary[:10]) до print(ary[:10, 1, 1]) - person JobJob; 21.06.2020
comment
@JobJob У вас есть идеи, возможно ли это со словарем? - person dreamcrash; 20.03.2021