sábado, 16 de abril de 2016

Paso de mensajes con Python (MPI)

MPI para python

MPI es un sistema estandarizado y portable de paso de mensajes, diseñado para funcionar en una amplia variedad de computadoras paralelas. El estándar define la sintaxis y semántica de un conjunto de funciones de librería que permiten a los usuarios escribir programas portables en los principales lenguajes utilizados por la comunidad científica (Fortran, C, C++). Desde su aparición, la especificación MPI se ha transformado en el estándar dominante en librerías de paso de mensajes para computadoras paralelas. En la actualidad se dispone de diversas implementaciones, algunas provistas por los fabricantes de computadoras de alta performance, hasta otras de reconocidos proyectos open source, tales como MPICH10 y LAM/MPI,11 muy utilizadas en los clúster de PC’s tipo Beowulf.
A pesar de los idiomas más apropiados para la computación paralela son C o Fortran, muchos investigadores prefieren lenguajes basados ​​en la matriz (como Python o Matlab) más de C y Fortran para su facilidad de uso. En particular, Python ha vuelto cada vez más popular. Por desgracia, Python no es muy adecuado para la computación de alto rendimiento y sus capacidades de las paralelas son todavía poco desarrollado. Sin embargo, por la misma razón que Python es un lenguaje excelente para el diseño de algoritmos y para resolver problemas que no requieren el máximo rendimiento, Python es una herramienta excelente en el desarrollo de código paralelo. En general, la programación en paralelo es mucho más difícil y compleja que en serie. Esto hace que la programación paralela en Python grande para la creación de prototipos y para pequeñas y medianas códigos. Incluso puede considerarse adecuado para la producción si la comunicación no es muy frecuente y el rendimiento no es la principal preocupación.
MPI para Python proporciona ataduras de la Message Passing Interface estándar (MPI) para el lenguaje de programación Python, permitiendo que cualquier programa de Python para aprovechar múltiples procesadores.

Funciones

Este módulo proporciona  la función spawn() (semilla), un front-end para diversas funciones específicas de la plataforma para el lanzamiento de otro programa en un sub-proceso. 

Ejemplo: 
Compute Pi - Master (or parent, or client) side:
#!/usr/bin/env python
from mpi4py import MPI
import numpy
import sys

comm = MPI.COMM_SELF.Spawn(sys.executable,
                           args=['cpi.py'],
                           maxprocs=5)

N = numpy.array(100, 'i')
comm.Bcast([N, MPI.INT], root=MPI.ROOT)
PI = numpy.array(0.0, 'd')
comm.Reduce(None, [PI, MPI.DOUBLE],
            op=MPI.SUM, root=MPI.ROOT)
print(PI)

comm.Disconnect()


Comm. Send buf , dest = 0 , tag = 0 
Realiza un envío básica. Este envío es una comunicación de punto a punto. Se envía información de exactamente un proceso para exactamente un otro proceso.
parámetros:
·         Comm ( Comm MPI ) - comunicador que pretende realizar la búsqueda
·         buf ( opción ) - datos que desea enviar
·         dest ( número entero ) - rango de destino
·         tag ( número entero ) - etiqueta del mensaje
Ejemplo:
import  numpy
from  mpi4py  import  MPI
a  =  numpy ([ 1 , 2 , 3 ])
if  MPI . COMM_WORLD . rank  ==  0 :
        MPI . COMM_WORLD . Send ( a ,  dest  =  1 )
else :
        MPI . COMM_WORLD . Recv ( a ,  source  =  0 )

 Comm. Recv buf , source = 0 , tag = 0 ,Status status= None 
punto a punto básico de recibir datos
parámetros:
·         Comm ( Comm MPI ) - comunicador que pretende realizar la búsqueda
·         buf ( opción ) - dirección inicial del búfer de recepción (escoja la ubicación recibo)
·         sourcenúmero entero ) - rango de fuente
·         tag ( número entero ) - etiqueta del mensaje
·         status ( Status ) - estado del objeto
Ejemplo:
from mpi4py import MPI
 
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
 
if rank == 0:
    data = {'a': 7, 'b': 3.14}
    comm.send(data, dest=1, tag=11)
elif rank == 1:
    data = comm.recv(source=0, tag=11)



Comm. Bcast buf , root = 0 
Difunde un mensaje desde el proceso con rango "raíz" a todos los otros procesos del grupo.
parámetros:
·         Comm ( comm MPI ) - comunicador a través del cual transmitir
·         buf ( opción ) - tampón
·         root ( int ) - rango de operación de raíz
Ejemplo:
import numpy
from mpi4py import MPI
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
 
#intialize
rand_num = numpy.zeros(1)
 
if rank == 0:
        rand_num[0] = numpy.random.uniform(0)
 
comm.Bcast(rand_num, root = 0)
print "Process", rank, "has the number", rand_num



Comm. Reduce sendbuf , recvbuf , Op op = MPI.SUM , root = 0 
Reduce los valores en todos los procesos en un solo valor en la raíz proceso.
parámetros:
·         Comm ( Comm MPI ) - comunicador que pretende realizar la búsqueda
·         sendbuf ( choice ) - dirección del buffer de envío
·         recvbuf ( choice ) - dirección del búfer de recepción (sólo significativa en la raíz)
·         op ( handle ) - reducir la operación
·         root ( int ) - rango de operación de raíz

Ejemplo:
import numpy
from mpi4py import MPI
comm = MPI.COMM_WORLD
 
rank = comm.Get_rank()
rankF = numpy.array(float(rank))
total = numpy.zeros(1)
comm.Reduce(rankF,total, op=MPI.MAX)


Comm. Scatter sendbuf , recvbuf , root 
Envía datos desde un proceso a todos los otros procesos en un comunicador (Longitud de recvbuf debe dividir  la longitud de sendbuf. De lo contrario, utilice Scatterv )
parámetros:
·         sendbuf ( choise ) - dirección del buffer de envío (significativo sólo en la raíz)
·         recvbuf ( choise ) - dirección del búfer de recepción
·         root ( int ) - rango de proceso de envío
Example:
import numpy
from mpi4py import MPI
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()
LENGTH = 3
 
#create vector to divide
if rank == 0:
        #the size is determined so that length of recvbuf evenly divides the
        #length of sendbuf
        x = numpy.linspace(1,size*LENGTH,size*LENGTH)
else:
        #all processes must have a value for x
        x = None
 
#initialize as numpy array
x_local = numpy.zeros(LENGTH)
 
#all processes must have a value for x. But only the root process
#is relevant. Here, all other processes have x = None.
comm.Scatter(x, x_local, root=0)
 
#you should notice that only the root process has a value for x that
#is not "None"
print "process", rank, "x:", x
print "process", rank, "x_local:", x_local


Comm. Gatherv (choice sendbuf[, choice recvbuf,tuple_int sendcounts, tuple_int displacements,MPI_Datatype sendtype], root=0)
Reunir Vector, recopilar datos para un proceso de todos los otros procesos en un grupo proporcionar diferente cantidad de datos y los desplazamientos en los lados que reciben
parámetros:
·         Comm ( Comm MPI ) - comunicador a través del cual para dispersar
·         sendbuf ( choice ) - tampón
·         recvbuf ( choise ) - tampón en el que recibir la sendbuf
·         sendcounts ( tuple_int ) - número de elementos para recibir de cada proceso (un número entero para cada proceso)
·         displacements tuple_int ) - número de elementos de distancia desde el primer elemento en la matriz receptora en el que comenzar añadiendo la matriz segmentada
·         sendtype ( MPI_Datatype ) - MPI tipo de datos de la memoria intermedia se envía (elección de sendbuf)
·         root ( int ) - proceso de partida para dispersar

Example:
# for correct performance, run unbuffered with 3 processes:
# mpiexec -n 3 python26 scratch.py -u
import numpy
from mpi4py import MPI
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
 
if rank == 0:
        x = numpy.linspace(0,100,11)
else:
        x = None
 
if rank == 2:
        xlocal = numpy.zeros(9)
else:
        xlocal = numpy.zeros(1)
 
if rank ==0:
        print "Scatter"
comm.Scatterv([x,(1,1,9),(0,1,2),MPI.DOUBLE],xlocal)
print ("process " + str(rank) + " has " +str(xlocal))
 
comm.Barrier()
if rank == 0:
        print "Gather"
        xGathered = numpy.zeros(11)
else:
        xGathered = None
comm.Gatherv(xlocal,[xGathered,(1,1,9),(0,1,2),MPI.DOUBLE])
print ("process " + str(rank) + " has " +str(xGathered))

Bibliografia de consulta



No hay comentarios:

Publicar un comentario