Ajude a manter o site livre, gratuito e sem propagandas. Colabore!
Em revisão
Em computação distribuída, rotinas de comunicação entre as instâncias de processamento são utilizadas para o compartilhamento de dados. Neste capítulo, vamos discutir sobre as rotinas de comunicação ponto-a-ponto, i.e. comunicações entre uma instância de processamento com outra.
Em revisão
O envio e recebimento de dados entre duas instâncias de processamento pode ser feita com as rotinas MPI_Send e MPI_Recv. A primeira é utilizada para o envio de um dado a partir de uma instância de processamento e a segunda é utilizada para o recebimento de um dado em uma instância de processamento.
A sintaxe da MPI_Send é
int MPI_Send( const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
e a sintaxe da MPI_Recv é
int MPI_Recv( void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)
O primeiro argumento é o ponteiro do buffer de dados. No caso do MPI_Send
é o ponteiro para a posição da memória do dado a ser enviado. No caso do MPI_Recv
é o ponteiro para a posição da memória do dado a ser recebido. O segundo argunto count
é o número de dados sequenciais a serem enviados. O argundo datatype
é o tipo de dado. O MPI suporta os seguintes tipos de dados
MPI_SHORT short int MPI_INT int MPI_LONG long int MPI_LONG_LONG long long int MPI_UNSIGNED_CHAR unsigned char MPI_UNSIGNED_SHORT unsigned short int MPI_UNSIGNED unsigned int MPI_UNSIGNED_LONG unsigned long int MPI_UNSIGNED_LONG_LONG unsigned long long int MPI_FLOAT float MPI_DOUBLE double MPI_LONG_DOUBLE long double MPI_BYTE char
Ainda sobre as sintaxes acima, o argumento source
é o identificador rank da instância de processamento. O argunmento tag
é um número arbitrário para identificar a operação de envio e recebimento. O argumento Comm
especifica o comunicador (MPI_COMM_WORLD
para aplicações básicas) e o último (somente para o MPI_Recv
) fornece informação sobre o status do recebimento do dado.
Vamos estudar o seguinte código abaixo.
O código acima pode rodado com pelo menos duas instâncias de processamento (veja as linhas 14-19). Nas linhas 28-29, o processo 0 envia o número 3.1416
(alocado na variável x
) para o processo 1. Nas linhas 32-33, o processo 1 recebe o número enviado pelo processo 0 e o aloca na variável y
.
Importante! As rotinas MPI_Send
e MPI_Recv
provocam a sincronização entre os processos envolvidos. Por exemplo, no código acima, no que o processo 0 atinge a rotina MPI_Send
ele ficará aguardando o processo 1 receber todos os dados enviados e só, então, irá seguir adiante no código. Analogamento, no que o processo 1 atingir a rotina MPI_Recv
, ele ficará aguardando o processo 0 enviar todos os dados e só, então, irá seguir adiante no código.
Em revisão
As rotinas MPI_Send
e MPI_Recv
podem ser utilizadas para o envio e recebimento de arrays. A sintaxe é a mesma vista acima, sendo que o primeiro argumento *buf
deve apontar para o início do array e o segundo argumento count
corresponde ao tamanho da array.
Vamos estudar o seguinte código. Nele, o processo 0 aloca e o processo 1 aloca . O processo 0 envia os valores para o processo 1. Então, o processo 1 recebe estes valores e os aloca em . Desta forma, a saída impressa no terminal é
(3.1) |
Verifique!
Em revisão
O MPI
também suporta rotinas MPI_Isend de envio e MPI_Irecv de recebimento assíncronos. Neste caso, o processo emissor envia o dado para outro processo e segue imediatamente a computação. O processo receptor deve conter uma rotina MPI_Irecv, mas também não aguarda sua conclusão para seguir a computação.
As sintaxes destas rotinas são semelhantes as das rotinas MPI_Send
e MPI_Recv
.
int MPI_Isend( const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request)
int MPI_Irecv( void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request)
O último argumento permite verificar os envios e recebimentos.
Vamos estudar o seguinte código.
Neste código, MPI_Status
e MPI_Request
são alocados nas linhas 26 e 27, respectivamente. O Processo 0 faz uma requisição de envio do número para o processo 1, não aguarda o recebimento e segue adiante. O processo 1 tem uma rotina de requisição de recebimento não assíncrona na linha 35. Neste momento, ele não necessariamente recebe o dado enviado pelo processador (isto pode ocorrer a qualquer momento mais adiante). Na linha 37, o valor de y
deve ainda ser , veja a saída do código.
$ mpic++ isendRecv.cc $ $ mpirun -np 2 ./a.out x = 1.000000 x = 4.141600
Pode-se verificar se uma requisição de envio (ou recebimento) foi completata usando-se a rotina MPI_Test. A sua sintaxe é
int MPI_Test( MPI_Request *request, int *flag, MPI_Status *status)
O flag == 0
caso a requisição ainda não foi completada e flag == 1
caso a requisição foi executada.
No Código isendRecv.cc
acima, as linhas de código 39-41 são utilizadas para fazê-lo aguardar até que a requisição de recebimento seja completada. Desta forma, na linha 42 o valor de y
é (o valor enviado pelo processo 0. Verifique!
No Código isendRecv.cc
acima, as linhas 39-41 podem ser substituídas pela rotina MPI_Wait, a qual tem sintaxe
int MPI_Wait( MPI_Request *request, MPI_Status *status)
Verifique!
Em revisão
Faça um código MPI para ser executado com 2 processadores. Um processo aloca e o outro processo aloca . Logo, os processos trocam os valores, de forma que ao final o processo zero tem e o processo 1 tem .
Faça um código MPI para ser executado com 2 processadores. O processo 0 aloca um vetor de elementos randômicos em ponto flutuante, envia o vetor para o processo 1. O processo 0, imprime no terminal a soma dos termos do vetor e o processo 1 imprime o produto dos termos do vetor.
Faça um código MPI para computar a média
(3.2) |
onde é um número em ponto flutuante e . Para a comunicação entre os processos, utilize apenas as rotinas MPI_Send
e MPI_Recv
.
Faça um código MPI para computação do produto interno entre dois vetores
(3.3) | |||
(3.4) |
Para a comunicação entre os processos, utilize apenas as rotinas MPI_Send
e MPI_Recv
. O processo 0 deve receber os resultados parciais dos demais processos e escrever na tela o valor computado do produto interno.
Modifique o código do exercício anterior (Exercício 3.2.4) de forma a fazer a comunicação entre os processos com as rotinas MPI_Isend
e MPI_Irecv
. Há vantagem em utilizar estas rotinas? Se sim, quais?
As informações preenchidas são enviadas por e-mail para o desenvolvedor do site e tratadas de forma privada. Consulte a Política de Uso de Dados para mais informações. Aproveito para agradecer a todas/os que de forma assídua ou esporádica contribuem enviando correções, sugestões e críticas!