c - 如何使用 MPI_Scatterv 将块大小发送到特定进程?
问题描述
随着使用
MPI_Scatterv(sendbuf[], sendcounts[], displs[], sendtype, recvbuf[], recvcount, recvtype, root, comm)
两个数组用于处理要发送到特定进程的可变长度数据块大小:sendcounts 和 displs。第一个是要发送到每个进程的元素数,而 displs 是 sendbuf 的起始索引,从中计算 sendcounts - 但每个进程的接收缓冲区长度相同。在这种情况下,我如何告诉每个进程它应该读取其 recbuf[] 的多少元素来处理?即进程 0 将获得 1 个元素,进程 1 将获得 3 个元素,但它们都有 recbuf[] 长度为 4 个元素。
解决方案
我发现的一个简单解决方案就是为每个等级初始化 sendcounts[] 数组。当相同的数据生成的次数与所涉及的等级一样多时,这将浪费一些内存,但是这样所有的数据都将具有相同的数据,并且都将确切地知道要从其特定的 recbuf 中读取多少元素。以下是根据这种方法的实施示例。如果我以任何方式做错了,请看一下并纠正我 - 欢迎所有评论。
编辑2:
@GillesGouaillardet 基于您的第二个答案(关于 f())我再次修改了代码,现在每个等级都根据函数输出获取其 recbuf 长度 - 现在除了根等级之外不使用 recbuf 数组。
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define DISPLACEMENT_SIZE 4
int getsendcount(int);
int main(int argc, char **argv)
{
int rank, size;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
int *rcvbuf = malloc(getsendcount(rank) * sizeof(int));
// root node will initialize input array of data and displacements when only root needs them for Scatter
if(!rank)
{
int *intab, *sendcounts, *displs;
int displacement = 0;
displs = malloc(size * sizeof(int));
sendcounts = malloc(size * sizeof(int));
int f = 0, mainindex = 0;
intab = malloc(size * DISPLACEMENT_SIZE * sizeof(int));
// every rank will get its own chunk of data, but all will get SAME copy
for(int i=0; i < size; i++)
{
*(sendcounts + i) = getsendcount(i);
}
// generating input data array
for(int i=0; i < size; i++)
{
for(int j=0; j < DISPLACEMENT_SIZE; j++)
{
*(intab+mainindex) = 1*f;
mainindex++;
}
f += 10;
}
// initializing displacements array, every DISPLACEMENT_SIZE fields for each rank
for(int i=0; i < size; i++)
{
*(displs + i) = displacement;
displacement += DISPLACEMENT_SIZE;
}
// debug block to see values
for(int i=0; i < size; i++)
{
printf("displs[%i] = %i, sendcounts[%i] = %i\n", i, *(displs+i), i, sendcounts[i]);
}
putchar('\n');
for(int i=0; i < mainindex; i++)
{
printf("%i ", *(intab + i));
}
putchar('\n');
MPI_Scatterv(intab, sendcounts, displs, MPI_INT,rcvbuf, getsendcount(rank), MPI_INT, 0, MPI_COMM_WORLD);
}
else
{
MPI_Scatterv(NULL, NULL, NULL, NULL ,rcvbuf, getsendcount(rank), MPI_INT, 0, MPI_COMM_WORLD);
}
printf("this is proces %i, got: sendcounts %i\n", rank, getsendcount(rank));
for(int i=0; i < getsendcount(rank); i++)
{
printf("Process %i my %i buffer value is %i\n ", rank, i, *(rcvbuf + i));
}
MPI_Finalize();
return 0;
}
int getsendcount(int i)
{
return i - (i/DISPLACEMENT_SIZE * DISPLACEMENT_SIZE) + 1;
}
推荐阅读
- xml - 当前日期时间超过xml模板odoo 12中指定的截止日期时隐藏表格
- spring-boot - Spring Boot 社交登录和谷歌日历 API
- c# - 添加不同的列表
到 DataGridView 中的 DataGridViewComboBoxCell - rxjs - 我如何对这个处理可观察对象的函数进行单元测试
- node.js - 我正在尝试使用 docker 文件对我的节点应用程序进行 dockerize,但它抛出错误:找不到模块'/app/app.js'
- kubernetes - 如何在 helm-couchdb 应用程序中添加 metric-server
- rest - 如何使用胶子插件实现休息客户端
- python - 从多维列表中提取特定值
- .net - 使用数据集绑定的行和标题结构清除 DataGridView
- java - 使字符串连续 x 没有所需的最小更改。A,然后在 (nx) 个 B 之后