无法在C/MPI中计算数组中大于x的数组元素
所以,我有一个问题,我有一个数组,我必须找到数组中大于索引无法在C/MPI中计算数组中大于x的数组元素,c,mpi,C,Mpi,所以,我有一个问题,我有一个数组,我必须找到数组中大于索引k的数字的计数。因此,我实施了一个master-worker策略,其中我有一个负责I/O并将工作分配给工人的master。在主线程中,我创建了一个矩阵形状的数组,因此我可以轻松地将子数组传递给工作人员(我知道这听起来很奇怪)。然后在主线程中,我读取子数组输入的所有值,并将comp(比较值)设置为k索引值的值 然后我将工作部分大小、比较值和工作数据传递给所有线程(包括获得其工作份额的主线程)。最后,每个工作人员都完成自己的工作,并向主控台报
k
的数字的计数。因此,我实施了一个master-worker策略,其中我有一个负责I/O并将工作分配给工人的master。在主线程中,我创建了一个矩阵形状的数组,因此我可以轻松地将子数组传递给工作人员(我知道这听起来很奇怪)。然后在主线程中,我读取子数组输入的所有值,并将comp
(比较值)设置为k
索引值的值
然后我将工作部分大小、比较值和工作数据传递给所有线程(包括获得其工作份额的主线程)。最后,每个工作人员都完成自己的工作,并向主控台报告其结果,当从工作人员接收数据时,将其值添加到自己的值中,然后在屏幕上打印总结果
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <math.h>
int main(int argc, char *args[]){
int rank, psize;
MPI_Status status;
MPI_Init(&argc, &args);
MPI_Comm_size(MPI_COMM_WORLD, &psize);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int *workvet, worksize, comp;
if(rank == 0){
int tam, k;
int **subvets, portion;
scanf("%d", &tam);
scanf("%d", &k);
portion = ceil((float)tam/(float)psize);
subvets = malloc(sizeof(int) * psize);
for(int i = 0; i < psize; i++)
subvets[i] = calloc(portion, sizeof(int));
for(int i = 0; i < psize; i++){
for(int j = 0; j < portion; j++){
if((i*j+j) < tam)
scanf("%d ", &subvets[i][j]);
if((i*j+j) == k)
comp = subvets[i][j];
}
}
for(int i = 1; i < psize; i++){
MPI_Send(&portion, 1, MPI_INT, i, i, MPI_COMM_WORLD);
MPI_Send(&comp, 1, MPI_INT, i, i, MPI_COMM_WORLD);
MPI_Send(subvets[i], portion, MPI_INT, i, i, MPI_COMM_WORLD);
}
workvet = calloc(portion, sizeof(int));
workvet = subvets[0];
worksize = portion;
} else {
MPI_Recv(&worksize, 1, MPI_INT, 0, rank, MPI_COMM_WORLD, &status);
MPI_Recv(&comp, 1, MPI_INT, 0, rank, MPI_COMM_WORLD, &status);
workvet = calloc(worksize, sizeof(int));
MPI_Recv(workvet, worksize, MPI_INT, 0, rank, MPI_COMM_WORLD, &status);
}
int maior = 0;
for(int i = 0; i < worksize; i++){
if(workvet[i] > comp)
maior++;
}
if(rank == 0){
int temp;
for(int i = 1; i < psize; i++){
MPI_Recv(&temp, 1, MPI_INT, i, rank, MPI_COMM_WORLD, &status);
maior += temp;
}
printf("%d números maiores que %d", maior, comp);
} else {
MPI_Send(&maior, 1, MPI_INT, 0, rank, MPI_COMM_WORLD);
}
MPI_Finalize();
}
因此,我的程序应该计算有多少元素大于索引7的元素(对应于值8),在这种情况下,它应该返回2<代码>tam正在单元化 还有一些其他问题 您正在执行
scanf
以获取comp
的值,但在其下方的循环中,您正在为其分配一个新值(即提示的值被丢弃)。如果原始值被视为默认值(如果循环无法分配新值),那么这可能非常好,但对我来说,这似乎有点不稳定
AFAICT,您正在尝试在所有进程中循环workvet
。但是,对于客户端,这没有任何作用,因为您没有返回结果[见下文]
客户机正在发回maior
,但他们从未计算过它的值。而且,main没有收到该值。它自己计算一个
maior
在您发布的代码中没有定义。因此,它是统一的[即使在主要方面]
看起来您希望客户机发回其计算值的单个标量值maior
,但他们不进行计算
因此,客户机将主进程尝试求和的垃圾maior
值发回
您正在向客户端发送部分
,但客户端会将其作为工作大小
接收。并且,在main发送后,它将部分
分配给工作大小
。我建议在所有地方使用相同的名称,以减少混淆
您没有提供任何示例数据,因此很难在此处进一步调试。部分问题在于,subvets
中只有一些值是根据if
[或它看起来是这样的…]用主中的scanf
初始化的
因此,客户机将在给定的subvet
数组中循环可能的单位化值[发送给作为workvet
]接收它的客户机]
如果subvet
的设置循环在发送哪些值方面是正确的(即,只发送某些选定的值),我不确定您是否可以使用现有的2D数组方法执行所需操作
如果没有一个描述输入数据的问题语句以及您想用它做什么,那么很难预测什么是正确的代码,但是
一些猜测
您正在计算所有进程中的最高值
(在主进程中可能没有用),但是没有人用它做任何事情。我的猜测是,您只希望在客户端进程中计算此值。然后,将其作为maior
发送回main
然后,main可以对所有客户端的maior
值求和
更新:
实际上,我将
maior
更改为highest
,以便在此处发布该问题,因此这有点道理(葡萄牙语中maior更大),但在所有情况下都没有这样做
正如我提到的,我猜了很多——不用担心。旁注:事实上,你的英语相当好。你能翻译代码真是太好了。有些人用英语发帖,但把代码留在他们的母语中。这会让事情慢一点。有时候,我把代码放进谷歌翻译,只是想弄明白它的意思
我只是在没有翻译的情况下更新了代码,以反映我正在进行的工作。因此,对于subvets部分,我实际上认为这是一个矩阵,其中我将把它的每一行作为一个数组发送给每个工作线程,if语句只在达到数组大小之前读取,因此,剩下的值为0(因为我使用了calloc,所以这种方法适合我必须解决的问题) 实际上不需要2D数组。只需填充一个1D数组,然后将不同的偏移量和计数放入单个数组中即可(见下文) 通过尝试在单个函数
main
中执行所有操作,这可能是导致分离主任务和辅助任务时出现一些问题的原因
通过将内容拆分为[更多]函数,这可以使事情变得更简单。我们可以在master和worker中为相同的数据使用相同的变量名,而不会产生任何命名冲突
还有一条很好的格言……不要复制代码
各种MPI.*
调用需要很多参数,因为它们是通用的。将它们与包装函数隔离可以使事情更简单,调试更容易
请注意,MPI\u Send/MPI\u Recv
的第二个参数是一个计数,而不是字节数(因此,不是sizeof
)(即一个bug)。通过将它们放在包装函数中,可以在单个位置修复一次调用
我对分割逻辑做了一点小小的修改。在你的代码[AFAICT]中,你让主/主进程做了一些计算。这就是fi
10 // size
7 // k
1 2 3 4 5 6 7 8 9 10 // elements
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <math.h>
// _dbgprt -- debug print
#define _dbgprt(_fmt...) \
do { \
printf("%d: ",myrank); \
printf(_fmt); \
} while (0)
#ifdef DEBUG
#define dbgprt(_fmt...) \
_dbgprt(_fmt)
#else
#define dbgprt(_fmt...) \
do { \
} while (0)
#endif
int myrank; // current rank
int numproc; // number of processes in comm group
// dataload -- read in the data
int *
dataload(FILE *xfsrc,int worksize)
{
int *workvet;
// get enough space
workvet = calloc(worksize,sizeof(int));
// fill the array
for (int idx = 0; idx < worksize; ++idx)
fscanf(xfsrc,"%d",&workvet[idx]);
return workvet;
}
// docalc -- count number of values greater than limit
int
docalc(int *workvet,int worksize,int k)
{
int count = 0;
for (int idx = 0; idx < worksize; ++idx) {
if (workvet[idx] > k)
count += 1;
}
return count;
}
// sendint -- send some data
void
sendint(int rankto,int *data,int count)
{
int tag = 0;
// NOTE: second argument is an array _count_ and _not_ the number of bytes
MPI_Send(data,count,MPI_INT,rankto,tag,MPI_COMM_WORLD);
}
// recvint -- receive some data
void
recvint(int rankfrom,int *data,int count)
{
int tag = 0;
MPI_Status status;
MPI_Recv(data,count,MPI_INT,rankfrom,tag,MPI_COMM_WORLD,&status);
}
// worker -- perform all worker operations
void
worker(void)
{
int master = 0;
// get array count
int worksize;
recvint(master,&worksize,1);
// get limit value
int k;
recvint(master,&k,1);
// allocate space for data
int *workvet = calloc(worksize,sizeof(int));
// get that data
recvint(master,workvet,worksize);
// calculate number of elements higher than limit
int count = docalc(workvet,worksize,k);
// send back result
sendint(master,&count,1);
}
// master -- perform all master operations
void
master(int argc,char **argv)
{
int isfile;
FILE *xfsrc;
int workrank;
// get the data either from stdin or from a file passed on the command line
do {
isfile = 0;
xfsrc = stdin;
if (argc <= 0)
break;
xfsrc = fopen(*argv,"r");
if (xfsrc == NULL) {
perror(*argv);
exit(1);
}
isfile = 1;
} while (0);
// get number of data elements
int worksize;
fscanf(xfsrc,"%d",&worksize);
// get limit [pivot]
int k;
fscanf(xfsrc,"%d",&k);
dbgprt("master: PARAMS worksize=%d k=%d\n",worksize,k);
// read in the data array
int *workvet = dataload(xfsrc,worksize);
if (isfile)
fclose(xfsrc);
// get number of workers
// NOTE: we do _not_ have the master do calculations [for simplicity]
// usually, for large data, we want the master free to control things
int numworkers = numproc - 1;
// get number of elements for each worker
int workper = worksize / numworkers;
dbgprt("master: LOOP numworkers=%d workper=%d\n",numworkers,workper);
// send data to other workers
int remain = worksize;
int offset = 0;
int portion;
for (workrank = 1; workrank < numproc; ++workrank,
offset += portion, remain -= portion) {
// get amount for this worker
portion = workper;
// last proc must get all remaining work
if (workrank == (numproc - 1))
portion = remain;
dbgprt("master: WORK/%d offset=%d portion=%d\n",
workrank,offset,portion);
// send the worker's data count
sendint(workrank,&portion,1);
// send the pivot point
sendint(workrank,&k,1);
// send the data to worker
sendint(workrank,&workvet[offset],portion);
}
// accumulate count
int total = 0;
int count;
for (workrank = 1; workrank < numproc; ++workrank) {
recvint(workrank,&count,1);
total += count;
}
printf("%d numbers bigger than %d\n",total,k);
// do cross check of MPI result against a simple single process solution
#ifdef CHECK
count = docalc(workvet,worksize,k);
printf("master count was %d -- %s\n",
count,(count == total) ? "PASS" : "FAIL");
#endif
}
// main -- main program
int
main(int argc,char **argv)
{
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&numproc);
MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
// skip over program name
--argc;
++argv;
if (myrank == 0)
master(argc,argv);
else
worker();
MPI_Finalize();
return 0;
}