MPI_Send 和 MPI_Recv 未正确接收矩阵
Matrix not received properly with MPI_Send and MPI_Recv
我是使用 MPI 编程的新手,我有一个练习,我必须使用 MPI_Send 和 MPI_Recv 将 2 个矩阵相乘,同时将两个矩阵发送到我的进程并将结果发送回根进程。 (两个矩阵都是方阵,N等于进程数)
这是我写的代码:
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[]){
srand(time(NULL));
int rank, nproc;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
int **matrice = (int **)malloc(nproc * sizeof(int *));
for ( int i=0; i<nproc; i++)
matrice[i] = (int *)malloc(nproc * sizeof(int));
int **matrice1 = (int **)malloc(nproc * sizeof(int *));
for (int i=0; i<nproc; i++)
matrice1[i] = (int *)malloc(nproc * sizeof(int));
int **result = (int **)malloc(nproc * sizeof(int *));
for (int i=0; i<nproc; i++)
result[i] = (int *)malloc(nproc * sizeof(int));
if(rank == 0){
for(int i = 0; i < nproc; i++){
for(int j = 0; j < nproc; j++){
matrice[i][j] = (rand() % 20) + 1;
matrice1[i][j] = (rand() % 20) + 1;
}
}
for(int i = 1; i < nproc; i++){
MPI_Send(&(matrice[0][0]), nproc*nproc, MPI_INT, i, 1, MPI_COMM_WORLD);
MPI_Send(&(matrice1[0][0]), nproc*nproc, MPI_INT, i, 2, MPI_COMM_WORLD);
}
}else{
MPI_Recv(&(matrice[0][0]), nproc*nproc, MPI_INT, 0, 1, MPI_COMM_WORLD, &status);
MPI_Recv(&(matrice1[0][0]), nproc*nproc, MPI_INT, 0, 2, MPI_COMM_WORLD, &status);
}
for(int i = 0; i < nproc; i++){
result[i][j] = 0;
for(int j = 0; j < nproc; j++){
result[rank][i] += matrice[rank][j] * matrice1[j][i];
}
}
if(rank != 0){
MPI_Send(&result[rank][0], nproc, MPI_INT, 0, 'p', MPI_COMM_WORLD);
}
if(rank == 0){
for(int i = 1; i < nproc; i++){
MPI_Recv(&result[i][0], nproc, MPI_INT, i, 'p', MPI_COMM_WORLD, &status);
}
}
MPI_Finalize();
}
我遇到了 MPI_Send
或 MPI_Recv
的问题,因为我收到的矩阵只有第一行是正确的,第二行填充了 0,其他行是随机的。
我不明白是什么导致了这个问题。
I am having problems with MPI_Send or MPI_Recv because only the first
row of the matrice I receive is correct, the second row is filled with
0 and the others are random.
您正在调用 MPI_Send 如下:
MPI_Send(&(matrice[0][0]), nproc*nproc, MPI_INT, i, 1, MPI_COMM_WORLD);
所以告诉 MPI 您将从位置&(matrice[0][0])
开始发送nproc*nproc
个元素。 MPI_Send
期望那些 nproc*nproc
元素在内存中连续分配。因此,您的矩阵应该在内存中连续分配。您可以将此类矩阵的内存布局视为:
| ------------ data used in the MPI_Send -----------|
| row1 row2 ... rowN |
|[0, 1, 2, 3, N][0, 1, 2, 3, N] ... [0, 1, 2, 3, N]|
\---------------------------------------------------/
从一行的最后一个元素到下一行的第一个元素没有间隙。
很遗憾,您已将矩阵分配为:
int **matrice = (int **)malloc(nproc * sizeof(int *));
for ( int i=0; i<nproc; i++)
matrice[i] = (int *)malloc(nproc * sizeof(int));
它不是在内存中连续分配一个矩阵,而是分配一个指针数组,这些指针数组并不强制在内存中连续分配。您可以将该矩阵视为具有以下内存布局:
| ------------ data used in the MPI_Send ----------|
| row1 [0, 1, 2, 3, N] ... (some "random" stuff) |
\--------------------------------------------------/
row2 [0, 1, 2, 3, N] ... (some "random" stuff)
...
rowN [0, 1, 2, 3, N] ... (some "random" stuff)
从一行的最后一个元素到下一行的第一个元素可能存在内存间隙。因此,MPI_Send
不可能 知道 下一行的开始位置。这就是为什么您可以收到第一行,但不能收到其余行的原因。
您可以使用以下方法解决该问题
- 在内存中连续分配矩阵;
- 逐行发送矩阵。
最简单(并且性能更好)的解决方案是您使用第一种方法;检查此 SO Thread 以了解如何为二维数组动态分配连续的内存块。
我是使用 MPI 编程的新手,我有一个练习,我必须使用 MPI_Send 和 MPI_Recv 将 2 个矩阵相乘,同时将两个矩阵发送到我的进程并将结果发送回根进程。 (两个矩阵都是方阵,N等于进程数)
这是我写的代码:
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[]){
srand(time(NULL));
int rank, nproc;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
int **matrice = (int **)malloc(nproc * sizeof(int *));
for ( int i=0; i<nproc; i++)
matrice[i] = (int *)malloc(nproc * sizeof(int));
int **matrice1 = (int **)malloc(nproc * sizeof(int *));
for (int i=0; i<nproc; i++)
matrice1[i] = (int *)malloc(nproc * sizeof(int));
int **result = (int **)malloc(nproc * sizeof(int *));
for (int i=0; i<nproc; i++)
result[i] = (int *)malloc(nproc * sizeof(int));
if(rank == 0){
for(int i = 0; i < nproc; i++){
for(int j = 0; j < nproc; j++){
matrice[i][j] = (rand() % 20) + 1;
matrice1[i][j] = (rand() % 20) + 1;
}
}
for(int i = 1; i < nproc; i++){
MPI_Send(&(matrice[0][0]), nproc*nproc, MPI_INT, i, 1, MPI_COMM_WORLD);
MPI_Send(&(matrice1[0][0]), nproc*nproc, MPI_INT, i, 2, MPI_COMM_WORLD);
}
}else{
MPI_Recv(&(matrice[0][0]), nproc*nproc, MPI_INT, 0, 1, MPI_COMM_WORLD, &status);
MPI_Recv(&(matrice1[0][0]), nproc*nproc, MPI_INT, 0, 2, MPI_COMM_WORLD, &status);
}
for(int i = 0; i < nproc; i++){
result[i][j] = 0;
for(int j = 0; j < nproc; j++){
result[rank][i] += matrice[rank][j] * matrice1[j][i];
}
}
if(rank != 0){
MPI_Send(&result[rank][0], nproc, MPI_INT, 0, 'p', MPI_COMM_WORLD);
}
if(rank == 0){
for(int i = 1; i < nproc; i++){
MPI_Recv(&result[i][0], nproc, MPI_INT, i, 'p', MPI_COMM_WORLD, &status);
}
}
MPI_Finalize();
}
我遇到了 MPI_Send
或 MPI_Recv
的问题,因为我收到的矩阵只有第一行是正确的,第二行填充了 0,其他行是随机的。
我不明白是什么导致了这个问题。
I am having problems with MPI_Send or MPI_Recv because only the first row of the matrice I receive is correct, the second row is filled with 0 and the others are random.
您正在调用 MPI_Send 如下:
MPI_Send(&(matrice[0][0]), nproc*nproc, MPI_INT, i, 1, MPI_COMM_WORLD);
所以告诉 MPI 您将从位置&(matrice[0][0])
开始发送nproc*nproc
个元素。 MPI_Send
期望那些 nproc*nproc
元素在内存中连续分配。因此,您的矩阵应该在内存中连续分配。您可以将此类矩阵的内存布局视为:
| ------------ data used in the MPI_Send -----------|
| row1 row2 ... rowN |
|[0, 1, 2, 3, N][0, 1, 2, 3, N] ... [0, 1, 2, 3, N]|
\---------------------------------------------------/
从一行的最后一个元素到下一行的第一个元素没有间隙。
很遗憾,您已将矩阵分配为:
int **matrice = (int **)malloc(nproc * sizeof(int *));
for ( int i=0; i<nproc; i++)
matrice[i] = (int *)malloc(nproc * sizeof(int));
它不是在内存中连续分配一个矩阵,而是分配一个指针数组,这些指针数组并不强制在内存中连续分配。您可以将该矩阵视为具有以下内存布局:
| ------------ data used in the MPI_Send ----------|
| row1 [0, 1, 2, 3, N] ... (some "random" stuff) |
\--------------------------------------------------/
row2 [0, 1, 2, 3, N] ... (some "random" stuff)
...
rowN [0, 1, 2, 3, N] ... (some "random" stuff)
从一行的最后一个元素到下一行的第一个元素可能存在内存间隙。因此,MPI_Send
不可能 知道 下一行的开始位置。这就是为什么您可以收到第一行,但不能收到其余行的原因。
您可以使用以下方法解决该问题
- 在内存中连续分配矩阵;
- 逐行发送矩阵。
最简单(并且性能更好)的解决方案是您使用第一种方法;检查此 SO Thread 以了解如何为二维数组动态分配连续的内存块。