2016-04-28 2 views
1

Я использую mpi4py для распараллеливания моего кода. Я хочу передать две части данных, целое число и реальное число между узлами. Я также хотел бы использовать массивы и капитал Send и Recv функции, которые быстрее. Читая некоторые уроки, кажется, что это можно сделать, но я не могу найти примеров. Вот простой вариант того, что не работает:Как создать структуру для передачи между узлами с помощью mpi4py

import numpy 
from mpi4py import MPI 
comm = MPI.COMM_WORLD 
size = comm.Get_size() 
rank = comm.Get_rank() 

dt = numpy.dtype('int,float') 
if rank == 0: 
    recvBuffr = numpy.zeros(1,dt) 
    comm.Recv(recvBuffr, source = MPI.ANY_SOURCE) 
    print recvBuffr 

else: 
    result = rank*1.5 
    sendBuffr = numpy.zeros(1,dt) 
    sendBuffr[0][0] = rank 
    sendBuffr[0][1] = result 
    comm.Send(sendBuffr, dest=0) 

И ошибка:

Traceback (most recent call last): 
    File "mpitest.py", line 10, in <module> 
Traceback (most recent call last): 
    File "mpitest.py", line 18, in <module> 
    comm.Send(sendBuffr, dest=0) 
    comm.Recv(recvBuffr, source = MPI.ANY_SOURCE) 
    File "MPI/Comm.pyx", line 248, in mpi4py.MPI.Comm.Recv (src/mpi4py.MPI.c:78963) 
    File "MPI/Comm.pyx", line 237, in mpi4py.MPI.Comm.Send (src/mpi4py.MPI.c:78765) 
    File "MPI/msgbuffer.pxi", line 380, in mpi4py.MPI.message_p2p_recv (src/mpi4py.MPI.c:26730) 
    File "MPI/msgbuffer.pxi", line 366, in mpi4py.MPI._p_msg_p2p.for_recv (src/mpi4py.MPI.c:26575) 
    File "MPI/msgbuffer.pxi", line 375, in mpi4py.MPI.message_p2p_send (src/mpi4py.MPI.c:26653) 
    File "MPI/msgbuffer.pxi", line 358, in mpi4py.MPI._p_msg_p2p.for_send (src/mpi4py.MPI.c:26515) 
    File "MPI/msgbuffer.pxi", line 114, in mpi4py.MPI.message_simple (src/mpi4py.MPI.c:23528) 
    File "MPI/msgbuffer.pxi", line 114, in mpi4py.MPI.message_simple (src/mpi4py.MPI.c:23528) 
    File "MPI/msgbuffer.pxi", line 59, in mpi4py.MPI.message_basic (src/mpi4py.MPI.c:22718) 
KeyError: 'T{l:f0:d:f1:}' 
    File "MPI/msgbuffer.pxi", line 59, in mpi4py.MPI.message_basic (src/mpi4py.MPI.c:22718) 
KeyError: 'T{l:f0:d:f1:}' 

Я думаю, что это означает, что это не достаточно, чтобы использовать Numpy структурированный массив, и мне нужно используйте тип данных MPI. Я нашел в документации (https://mpi4py.scipy.org/docs/apiref/mpi4py.MPI.Datatype-class.html), что есть функция mpi4py.MPI.Datatype.Create_struct, которая выглядит так, как будто это может быть то, что я хочу, но я не понимаю, как ее использовать. В колонке док говорится:

Create_struct(...) 
    Datatype.Create_struct(type cls, blocklengths, displacements, datatypes) 

    Create an datatype from a general set of 
    block sizes, displacements and datatypes 

Спасибо за помощь!

ответ

2

Так, начиная с самого начала:

Это всегда можно получить вещи начал только с помощью кортежей Python, и очень удобные операторы травильных MPI4PY, чтобы сделать это, просто отправив кортеж:

from __future__ import print_function 
from mpi4py import MPI 
import numpy as np 

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

assert size > 1 

if rank == 0: 
    result = comm.recv(source = MPI.ANY_SOURCE, tag = MPI.ANY_TAG) 
    print(result) 
elif rank == 1: 
    comm.send((1, 3.14), dest = 0) 

Бег дает

$ mpirun -np 2 python send_tuple.py 
(1, 3.14) 

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

Для этого вам нужно знать, что память выложена из структуры, которая, как правило, недоступна вам (скажем) кортежем; операторы сообщений верхнего регистра в MPI4PY полагаются на numpy, что дает гарантии относительно макета памяти.

За то, как массив структур, вы можете использовать NumPy structured arrays:

>>> a = numpy.zeros(2, dtype=([('int',numpy.int32),('dbl',numpy.float64)])) 
>>> a 
array([(0, 0.0), (0, 0.0)], 
     dtype=[('int', '<i4'), ('dbl', '<f8')]) 

Так что теперь у нас есть массив структур, с первым полем был назван «ИНТ» и имеющий 4-байтовое целое тип, а второй - с именем 'dbl' и имеющий 8-байтовый тип с плавающей запятой.

После того как вы это, вы можете начать запрашивая расположение данных - найти размер отдельной структуры:

>>> print(a.nbytes/2) 
12 
>>> print(a.dtype.fields) 
mappingproxy({'dbl': (dtype('float64'), 4), 'int': (dtype('int32'), 0)}) 

Это первый говорит вам, насколько типа - число байтов между началом первый элемент и начало второго - и второй дает смещения в байтах для каждого элемента.То, что нужно для структуры:

>>> displacements = [a.dtype.fields[field][1] for field in ['int','dbl']] 
>>> print(displacements) 
[0, 4] 

Теперь вы можете начать создавать тип данных MPI для структуры и использовать его точно так же, как вы бы с MPI.INT или тому подобное. Единственный оставшийся трюк заключается в том, что при вызове Create_struct вы должны переводить из numpy dtypes в типы данных MPI, но это довольно просто. Следующий код дает старт:

#!/usr/bin/env python 
from __future__ import print_function 
from mpi4py import MPI 
import numpy as np 

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

assert size > 1 

def definetype(field_names, field_dtypes): 
    num = 2 
    dtypes = list(zip(field_names, field_dtypes)) 
    a = np.zeros(num, dtype=dtypes) 

    struct_size = a.nbytes // num 
    offsets = [ a.dtype.fields[field][1] for field in field_names ] 

    mpitype_dict = {np.int32:MPI.INT, np.float64:MPI.DOUBLE} #etc 
    field_mpitypes = [mpitype_dict[dtype] for dtype in field_dtypes] 

    structtype = MPI.Datatype.Create_struct([1]*len(field_names), offsets, field_mpitypes) 
    structtype = structtype.Create_resized(0, struct_size) 
    structtype.Commit() 
    return structtype 


if __name__ == "__main__": 
    struct_field_names = ['int', 'dbl'] 
    struct_field_types = [np.int32, np.float64] 
    mytype = definetype(struct_field_names, struct_field_types) 
    data = np.zeros(1, dtype=(list(zip(struct_field_names, struct_field_types)))) 

    if rank == 0: 
     comm.Recv([data, mytype], source=1, tag=0) 
     print(data) 
    elif rank == 1: 
     data[0]['int'] = 2 
     data[0]['dbl'] = 3.14 
     comm.Send([data, mytype], dest=0, tag=0) 

Бег дает

$ mpirun -np 2 python send_struct.py 
[(2, 3.14)] 
0

Если одна из отправленных частей данных является целым числом, то отправка ее как тега работает. (Тем не менее, так как это решение ограничиваются целым числом, я по-прежнему очень заинтересован в альтернативном ответ на мой вопрос.)

import numpy 
from mpi4py import MPI 
comm = MPI.COMM_WORLD 
size = comm.Get_size() 
rank = comm.Get_rank() 

if rank == 0: 
    result = numpy.zeros(1,float) 
    status=MPI.Status() 
    comm.Recv(result, source = MPI.ANY_SOURCE, status = status, tag = MPI.ANY_TAG) 
    print status.Get_tag(), result 

else: 
    result = numpy.array([rank*1.5,]) 
    i = 5 
    comm.Send(result, dest=0, tag=i) 

 Смежные вопросы

  • Нет связанных вопросов^_^