Engellemeyen İletişim

Önceki derste, sıralar arasında iletişim kurmak için MPI_Send ve MPI_Recv işlevlerini kullandık. Bu işlemlerin program akışını bloke ettiğini gördük. MPI_Send yalnızca program gönderme arabelleğini güvenli bir şekilde değiştirebildiğinde dönecek ve MPI_Recv yalnızca veriler alındıktan ve alma arabelleğine yazıldıktan sonra dönecektir. Bu şekilde iletişim kurmak güvenli ve basittir, ancak iletişim gerçekleşirken programın beklemesine neden olur. Genellikle veri beklerken gerçekleştirebileceğimiz hesaplamalar vardır bunun için asenkron bir iletişim şekline ihtiyaç vardır.

MPI standardı, gönderme ve alma işlevlerinin, MPI_Send ve MPI_Recv, engellenmeyen asenkron sürümlerini içerir: MPI_Isend ve MPI_Irecv. Bu işlevler hemen geri dönerek programın akışı üzerinde daha fazla kontrol sahibi olmanızı sağlar. Onları çağırdıktan sonra, gönderme veya alma arabelleğini değiştirmek güvenli değildir, ancak program diğer işlemlere devam etmekte serbesttir. Arabelleklerdeki verilere ihtiyaç duyduğunda, MPI_Wait ve MPI_Test işlevlerini kullanarak iletişim sürecinin tamamlandığından emin olması gerekir.

MPI_Isend

int MPI_Isend(
   void* data,
   int count,
   MPI_Datatype datatype,
   int destination,
   int tag,
   MPI_Comm communicator,
   MPI_Request* request)

data: gönderilen verinin başlangıcına işaret eden değişken

count: yollanacak eleman sayısı

datatype: yollanan verinin tipi

destination: verilerin gönderileceği programın sıra numarası

tag: bir mesaj etiketi (integer)

communicator: programlar arası iletişimi sağlayan obje

request: isteğin yapısına ilişkin işaretçi

MPI_Irecv

int MPI_Irecv(
   void* data,
   int count,
   MPI_Datatype datatype,
   int source,
   int tag,
   MPI_Comm communicator,
   MPI_Request* request)

data: alınacak verinin yazılacağı değişkenin başlangıcına işaret eden işaretçi

count: alınacak eleman sayısı

datatype: alınacak verinin tipi

source: verilerin alınacağı programın sıra numarası

tag: bir mesaj etiketi (integer)

communicator: programlar arası iletişimi sağlayan obje

status: MPI komutunun çıkış durumunu yazmak için bir işaretçi

request: isteğin yapısına ilişkin işaretçi

Asenkron fonksiyonlarda senkron fonksiyonlara kıyasla ek olarak bir request parametresi gerekir. Bu, program tarafından başlatılan her bir ayrı aktarımı takip etmek için kullanılır. MPI_Test işlevini kullanarak bir aktarımın durumunu kontrol etmek için kullanabilir veya aktarım tamamlanana kadar beklemek için MPI_Wait‘i çağırabilirsiniz.

Test and Wait

MPI_Test, bir istek tarafından belirtilen aktarımın durumunu döndürür ve MPI_Wait, geri dönmeden önce aktarımın tamamlanmasını bekler. İstek, MPI_Isend veya MPI_Irecv tarafından oluşturulabilir.

MPI_Test

int MPI_Test(
   MPI_Request* request,
   int * flag,
   MPI_Status* status)

request: test edilecek istek

flag: yollanacak eleman sayısı

status: bu komutun sonucunun yazılacağı işaretçi

MPI_Wait

int MPI_Wait(
   MPI_Request* request,
   MPI_Status* status)

request: beklenicek istek

status: bu komutun sonucunun yazılacağı işaretçi

Bu işlevler, MPI_Send ve MPI_Recv‘ye benzer şekilde kullanılabilir. Bir önceki derste bahsettiğimiz “Hello World!” mesajı gönderen programda MPI_Send ve MPI_Recv‘i, MPI_ISend, MPI_IRecv ve MPI_Wait kullanarak nasıl değiştirebileceğinizi aşağıdaki örnekten bakabilirsiniz.

#include <stdio.h>
#include <mpi.h>

int main(int argc, char** argv) {
  int rank, n_ranks;
  int my_first, my_last;
  int numbers = 10;
  MPI_Request request;

  // mpi programını başlatmak için Init fonksiyonunu çağırıyoruz
  MPI_Init(&argc, &argv);

  // mpi tarafından 2 veya 2 den fazla programın varlığını kontrol ediyoruz
  // eğer sadece bir program varsa programımız çökecektir
  MPI_Comm_size(MPI_COMM_WORLD,&n_ranks);
  if( n_ranks < 2 ){
    printf("This example requires at least two ranks");
    MPI_Finalize();
    return(1);
  }

  // programın sırasını elde etmek için Comm_rank fonksiyonunu çağırıyoruz
  MPI_Comm_rank(MPI_COMM_WORLD,&rank);

    // eğer programın sırası 0 ise send komutunu kullanarak sırası 1 olan
  // programa Hello, world!\n mesajını yolluyoruz
    // bu örnekte bir önceki örnekten farklı olarak
  // asenkron yollama fonksiyonunu kullanıyoruz
  if( rank == 0 ){
     char *message = "Hello, world!\n";
     MPI_Isend(message, 16, MPI_CHAR, 1, 0, MPI_COMM_WORLD, &request);
  }

    // eğer programın sırası 1 ise sırası 0 olan programdan
    // 16 uzunluğunda bir karakter listesi bekliyoruz
    // MPI_Irecv ve MPI_Wait fonksiyonları arasında
    // beklediğimiz mesajı içermeyen işlemler gerçekleştirerek
    // iletişimi ve işlemi aynı anda yapabiliriz
  if( rank == 1 ){
     char message[16];
     MPI_Status status;
     MPI_Irecv(message, 16, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &request);
     MPI_Wait( &request, &status );
     printf("%s",message);
  }

  // Call finalize at the end
  return MPI_Finalize();
}