我是MPI的初学者,当我尝试将数组拆分成一些子数组时,我遇到了一个问题。
更确切地说,我有一个数组,让我们说int a[10]={1,3,2,7,8,12,5,7,68,10}
,我在X进程上运行我的程序(此时我正在使用8但可能更多或更少)。
我希望在此数组的一部分上发送给每个进程,例如,对于我的数组,此时每个进程都会收到process0 = {1, 3}
,process2 = {2, 7}
之类的内容等等。直到{{ 1}}。
在我发送每个子阵列后,我将对每个子阵列进行一些操作,之后我想将所有子阵列合并到一个后面。
我在google上搜索了很多,我看到了一些使用process7 = 68, 10
和MPI_Send
或 MPI_Recv
和MPI_Scatter
和我的示例尝试了一些方法,但我尝试过的一切......都没有成功,我收到错误或者
空指针......
我的代码:
MPI_Gather
我曾经尝试过哪些我无法得到结果,我发表了评论,我做错了什么
非常感谢您的帮助。
答案 0 :(得分:2)
虽然dreamcrash已经建议你可以使用scatter& amp;聚集起来,我会更加重视这一点。 尽可能使用内置集合操作。不要试图自己重建它们。不仅代码更清晰,更容易理解,它也会明显更快,并允许MPI实现的各种优化。您的示例(假设gem
可被N
整除)变为:
size
请注意,if (rank == ROOT) {
for (int i = 0; i < N; i++) {
A[i] = rand() % 10;
}
}
MPI_Scatter(A, count, MPI_INT, localArray, count, MPI_INT, ROOT, MPI_COMM_WORLD);
//---------------SORT THE localArray-------------------
MPI_Gather(localArray, count, MPI_INT, A, count, MPI_INT, ROOT, MPI_COMM_WORLD);
MPI_Finalize();
排名正确参与计算,并使用scatter / gather将数据发送给自身,而无需任何其他代码路径。
现在,由于您的示例明确使用ROOT
,N=10
不能被size=8
整除,因此这是一个正常运行的版本。我们的想法是在整个remainder
排名中均匀分配整数除法的remainder
(每个排名都需要一个额外的元素)。无论使用send / recv还是scatter / gather,你都必须这样做。使用分散/聚集,您可以使用MPI_Scatterv
/ MPI_Gatherv
变体,这些变体采用sendcounts
数组(每个等级获得多少元素)和displacements
(每个地方的偏移量)全球范围内的一部分):
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define N 32
int A[N];
int main(int argc, char *argv[]) {
int size;
int rank;
const int ROOT = 0;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// compute the work distribution
int remainder = N % size;
int local_counts[size], offsets[size];
int sum = 0;
for (int i = 0; i < size; i++) {
local_counts[i] = N / size;
if (remainder > 0) {
local_counts[i] += 1;
remainder--;
}
offsets[i] = sum;
sum += local_counts[i];
}
int localArray[local_counts[rank]];
if (rank == ROOT) {
for (int i = 0; i < N; i++) {
A[i] = rand() % 10;
}
}
MPI_Scatterv(A, local_counts, offsets, MPI_INT, localArray, local_counts[rank], MPI_INT, ROOT, MPI_COMM_WORLD);
//---------------SORT THE localArray-------------------
MPI_Gatherv(localArray, local_counts[rank], MPI_INT, A, local_counts, offsets, MPI_INT, ROOT, MPI_COMM_WORLD);
MPI_Finalize();
return 0;
}
答案 1 :(得分:1)
更改您的代码:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define N 32
int A[N]; // this should be global
int main(int argc, char *argv[]) {
int size;
int rank;
const int VERY_LARGE_INT = 999999;
const int ROOT = 0;
int tag = 1234;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int count = N / size ;
int *localArray = (int *) malloc(count * sizeof(int));
int localMin; // minimum computed on rank i
int globalMin; // will only be valid on rank == ROOT
if (rank == ROOT) {
for (int i = 0; i < N; i++) {
A[i] = rand() % 10;
}
// master local copy
for (int i = 0; i < count; i++)
localArray[i] = A[i];
for (int dest = 1; dest < size; ++dest) {
MPI_Send(&A[dest* count], count, MPI_INT, dest, tag, MPI_COMM_WORLD);
printf("P0 sent a %d elements to P%d.\n", count, dest);
}
localMin = VERY_LARGE_INT;
for (int source = 1; source < size; source++)
{
MPI_Recv(localArray, count, MPI_INT, source, 2, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);
//--------------------------------I CANT GET RESULT HERE-------------------------------------
printf("Received results from task %d\n", source);
}
}
else
{
MPI_Recv(localArray, count, MPI_INT, ROOT, tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
//.. do something
MPI_Send(localArray, count, MPI_INT, ROOT, 2, MPI_COMM_WORLD);
}
MPI_Finalize();
return 0;
}
一些错误:
数组A
是全局的,因此所有进程都拥有它,您最多
可能只想为主进程分配它;
我将N / (size - 1)
更改为N / size
,但请注意这一点
仅在N %% size == 0时有效,因此您可能想要处理反对
场景。
由于master将拥有全局数组的子副本,因此在将数据发送到从属服务器之前,我正在执行从A到本地数组的本地副本:
// master local copy
for (int i = 0; i < count; i++)
localArray[i] = A[i];
合并部分有一个小错误,主设备和从设备正在使用不同的标签,导致死锁。这就是为什么我也改变了这个原因:
MPI_Send(localArray, count, MPI_INT, ROOT, tag, MPI_COMM_WORLD);
到
MPI_Send(localArray, count, MPI_INT, ROOT, 2, MPI_COMM_WORLD);
两者现在都有相同的标签(2);
您可以使用分散和收集来实现此代码,并且可以更清晰地看到here一些示例。
另一个镜像问题是如果您使用的是C语言而不是int *localArray = (int *) malloc(count * sizeof(int));
,那么您应该int *localArray = malloc(count * sizeof(int));
看here为什么。