▶ 使用 MPI 派生数据类型,减少数据在传输过程中的耗时

● MPI_Type_create_struct() 范例代码

 {
const int globalSize = ;
int globalDataInt[globalSize], globalDataDouble[globalSize];
int i, comSize, comRank, randomInt, sumInt;
double sumDouble; MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &comSize);
MPI_Comm_rank(MPI_COMM_WORLD, &comRank); // 创建派生数据类型,包含 1 个整形数组,1 个浮点数组和 1 个整形的结构。创建过程只与数据类型有关而与数据的值无关,每个进程都进行了创建
int blockLength[] = { globalSize,globalSize, }; // 各成员的长度
MPI_Aint globalDataInt_p, globalDataDouble_p, randomInt_p; // 获取各成员的地址,以计算偏移量
MPI_Get_address((void *)globalDataInt, &globalDataInt_p);
MPI_Get_address((void *)globalDataDouble, &globalDataDouble_p);
MPI_Get_address((void *)&randomInt, &randomInt_p);
MPI_Aint displacement[] = { , globalDataDouble_p - globalDataInt_p,randomInt_p - globalDataInt_p };// 计算各成员地址关于第一个成员的偏移量
int type[] = { MPI_INT,MPI_DOUBLE,MPI_INT }; // 各成员的数据类型
MPI_Datatype newType; // 调用内建函数创建新类型
MPI_Type_create_struct(, blockLength, displacement, type, &newType);
MPI_Type_commit(&newType); // 提交新类型,以便像 MPI_Datatype 那样使用 if (comRank == )
{
for (i = ; i < globalSize; globalDataInt[i] = i, globalDataDouble[i] = (double)i, i++);
randomInt = ;
} MPI_Bcast(globalDataInt, , newType, , MPI_COMM_WORLD);// 发送数据到各进程,使用的数据指针是派生数据类型中首个成员的数据的指针 for (i = sumInt = , sumDouble = 0.0; i < globalSize; i++)
{
sumInt += globalDataInt[i];
sumDouble += globalDataDouble[i];
}
printf("Size = %d, rank = %d, resultInt = %d, resultDouble = %f, randomInt = %d\n", comSize, comRank, sumInt, sumDouble, randomInt); MPI_Type_free(&newType);
MPI_Finalize();
return ;// 输出结果:八个进程乱序输出诸如 Size = 8, rank = 4, resultInt = 28, resultDouble = 28.000000, randomInt = 120994 的结果
}

● 用到的函数

 // 创建派生数据类型
MPI_METHOD MPI_Type_create_struct(
_In_range_(>= , ) int count, // 成员个数
_mpi_reads_(count) const int array_of_blocklengths[], // 各成员的长度,1 为标量,大于 1 为矢量
_mpi_reads_(count) const MPI_Aint array_of_displacements[], // 各成员地址关于第一个成员的偏移量,以便 MPI 整合数据
_mpi_reads_(count) const MPI_Datatype array_of_types[], // 成员数据类型
_Out_ MPI_Datatype* newtype // 传入一个 MPI_Datatype* 类型的指针,用于输出所创建的类型
); // 提交创建的数据类型以便使用
MPI_METHOD
MPI_Type_commit(_In_ MPI_Datatype* datatype);// 传入使用函数 MPI_Type_create_struct() 创建的类型,之后就能像使用 MPI_Datatype 那样使用创建的数据类型了 MPI_METHOD MPI_Type_free(_Deref_out_range_(== , MPI_DATATYPE_NULL) _Inout_ MPI_Datatype* datatype);
// 使用自定义的类型需要额外的空间开销,是使用完毕后要释放空间,需要传入创建个点类型

▶ 其他几个派生数据类型的函数原型

 MPI_METHOD MPI_Type_contiguous(
_In_range_(>= , ) int count, // 数据个数
_In_ MPI_Datatype oldtype, // 原数据类型
_Out_ MPI_Datatype* newtype // 新数据名
); MPI_METHOD MPI_Type_vector(
_In_range_(>= , ) int count, // 数据个数
_In_range_(>= , ) int blocklength, // 每个数据的宽度(即每个数据本身可以是一个矢量)
_In_ int stride, // 相邻数据之间的跨步(&a[n+1] - &a[n],a[n] 内部不是什么不重要)
_In_ MPI_Datatype oldtype, // 原数据类型
_Out_ MPI_Datatype* newtype // 新数据名
); MPI_METHOD MPI_Type_create_hvector(
_In_range_(>= , ) int count, // 元素个数
_In_range_(>= , ) int blocklength, // 元素宽度(个数为单位)
_In_ MPI_Aint stride, // 相邻元素跨度(字节为单位)
_In_ MPI_Datatype oldtype, // 原数据类型
_Out_ MPI_Datatype* newtype // 新数据名
); MPI_METHOD MPI_Type_indexed(
_In_range_(>=, ) int count, // 元素个数
_mpi_reads_(count) const int array_of_blocklengths[], // 元素宽度
_mpi_reads_(count) const int array_of_displacements[], // 每个元素关于首元的偏移量
_In_ MPI_Datatype oldtype, // 原数据类型
_Out_ MPI_Datatype* newtype // 新数据名
);

● 函数 MPI_Type_contiguous() 和 MPI_Type_vector() 范例

 // 将整形数组中连续 7 个元素封装为一个 newType 进行消息传递
{
MPI_Datatype newType;
MPI_Type_contiguous(, MPI_INT, &newType);
MPI_Type_commit(&newType);
} // 将二维数组 a[11][13] 中某两列前 7 个元素封装为一个 newType 进行消息传递
{
MPI_Datatype newType;
MPI_Type_vector(, , , MPI_INT, &newType);// 注意每个元素宽度为 2,跨度为 13(即一行的元素个数)
MPI_Type_commit(&newType);
}

● 函数 MPI_Type_create_hvector() 的范例

 {
const int dataSize = ;
MPI_Datatype int3, type;
int comRank, comSize, i, data[dataSize]; MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &comSize);
MPI_Comm_rank(MPI_COMM_WORLD, &comRank); MPI_Type_contiguous(, MPI_INT, &int3);// 连续三个整形组一个 int3
MPI_Type_commit(&int3);
MPI_Type_create_hvector(, , * sizeof(int), int3, &type);// 一个 type 包含 3 个元素,每个元素由连续两个 int3 组成,3 个元素之间跨度为 7 个整形
MPI_Type_commit(&type);
if (comRank == )// 0 号进程发送一个 type 给 1 号进程
{
for (i = ; i < dataSize; data[i] = i, i++);
MPI_Send(data, , type, ,, MPI_COMM_WORLD);
}
if (comRank == )
{
for (i = ; i < dataSize; data[i++] = -);
MPI_Recv(data, , type, , , MPI_COMM_WORLD,MPI_STATUS_IGNORE);
for (i = ; i < dataSize; i++)
printf("%3d, ", data[i]);
fflush(stdout);
} MPI_Finalize();
return ;
}

● 输出结果,连续 6 个元素断一下

D:\Code\MPI\MPIProjectTemp\x64\Debug>mpiexec -n  -l MPIProjectTemp.exe
[] , , , , , , -, , , , , , , -, , , , , , , -,

● 函数 MPI_Type_indexed() 范例

 {
const int dataSize = ;
MPI_Datatype int3, type;
int comRank, comSize, i, data[dataSize], blocklen[] = { , , }, displacement[] = { , , }; MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &comSize);
MPI_Comm_rank(MPI_COMM_WORLD, &comRank); MPI_Type_contiguous(, MPI_INT, &int3);
MPI_Type_commit(&int3);
MPI_Type_indexed(, blocklen, displacement, int3, &type);// 一个 type 包含 3 个元素,每个元素分别由 blocklen[i] 个 int3 组成,各元素之间跨度为 displacement[i] 个 int3 形
MPI_Type_commit(&type); if (comRank == )
{
for (i = ; i < dataSize; data[i] = i, i++);
MPI_Send(data, , type, , , MPI_COMM_WORLD);
}
if (comRank == )
{
for (i = ; i < dataSize; data[i++] = -);
MPI_Recv(data, , type, , , MPI_COMM_WORLD, MPI_STATUSES_IGNORE);
for (i = ; i<dataSize; i++)
printf("%3d, ", data[i]);
fflush(stdout);
} MPI_Finalize();
return ;
}

● 输出结果,分别为 6 个、9 个、3 个元素,偏移位置分别为第 0,3,8 个 int3 的起点位置

D:\Code\MPI\MPIProjectTemp\x64\Debug>mpiexec -n  -l MPIProjectTemp.exe
[] , , , , , , -, -, -, , , , , , , , , , -, -, -, -, -, -, , , ,

▶ 其他派生数据类型,等待补全

 MPI_METHOD MPI_Type_create_hindexed(
_In_range_(>= , ) int count,
_mpi_reads_(count) const int array_of_blocklengths[],
_mpi_reads_(count) const MPI_Aint array_of_displacements[],
_In_ MPI_Datatype oldtype,
_Out_ MPI_Datatype* newtype
); MPI_METHOD MPI_Type_create_hindexed_block(
_In_range_(>= , ) int count,
_In_range_(>= , ) int blocklength,
_mpi_reads_(count) const MPI_Aint array_of_displacements[],
_In_ MPI_Datatype oldtype,
_Out_ MPI_Datatype* newtype
); MPI_METHOD MPI_Type_create_indexed_block(
_In_range_(>= , ) int count,
_In_range_(>= , ) int blocklength,
_mpi_reads_(count) const int array_of_displacements[],
_In_ MPI_Datatype oldtype,
_Out_ MPI_Datatype* newtype
); MPI_METHOD MPI_Type_create_subarray(
_In_range_(>= , ) int ndims,
_mpi_reads_(ndims) const int array_of_sizes[],
_mpi_reads_(ndims) const int array_of_subsizes[],
_mpi_reads_(ndims) const int array_of_starts[],
_In_range_(MPI_ORDER_C, MPI_ORDER_FORTRAN) int order,
_In_ MPI_Datatype oldtype,
_Out_ MPI_Datatype* newtype
); _Pre_satisfies_(order == MPI_DISTRIBUTE_DFLT_DARG || (order >= MPI_DISTRIBUTE_BLOCK && order <= MPI_DISTRIBUTE_NONE))
MPI_METHOD MPI_Type_create_darray(
_In_range_(>= , ) int size,
_In_range_(>= , ) int rank,
_In_range_(>= , ) int ndims,
_mpi_reads_(ndims) const int array_of_gsizes[],
_mpi_reads_(ndims) const int array_of_distribs[],
_mpi_reads_(ndims) const int array_of_dargs[],
_mpi_reads_(ndims) const int array_of_psizes[],
_In_ int order,
_In_ MPI_Datatype oldtype,
_Out_ MPI_Datatype* newtype
);

MPI 派生数据类型 MPI_Type_create_struct(),MPI_Type_contiguous(),MPI_Type_vector(),MPI_Type_create_hvector(),MPI_Type_indexed()的更多相关文章

  1. MPI自定义数据类型

    自定义数据类型 1.数据类型辅助函数 MPI_Type_commit int MPI_Type_commit( MPI_Datatype *datatype ); 在通信中使用数据类型对象之前,必须提 ...

  2. MPI n 体问题

    ▶ <并行程序设计导论>第六章中讨论了 n 体问题,分别使用了 MPI,Pthreads,OpenMP 来进行实现,这里是 MPI 的代码,分为基本算法和简化算法(引力计算量为基本算法的一 ...

  3. 【MPI学习6】MPI并行程序设计模式:具有不连续数据发送的MPI程序设计

    基于都志辉老师<MPI并行程序设计模式>第14章内容. 前面接触到的MPI发送的数据类型都是连续型的数据.非连续类型的数据,MPI也可以发送,但是需要预先处理,大概有两类方法: (1)用户 ...

  4. XML学习笔记5——XSD复杂数据类型

    和简单数据类型对应就是复杂数据类型了,XML元素的数据类型可以是简单数据类型,也可以是复杂数据类型,而XML属性的数据类型就只能是简单数据类型.这篇笔记,就来学习一下XSD中的复杂数据类型了. 1.定 ...

  5. C语言中的数据类型

    基本数据类型: int float double char void 派生数据类型: 数据类型修饰符 + 基本数据类型 = 派生数据类型 signed  和 unsigned 类型 unsigned ...

  6. MPI Hello World

    ▶<并行程序设计导论>第三章(用 MPI 进行分布式内存编程)的第一个程序样例. ●  代码 #include <stdio.h> #include <string.h& ...

  7. xml schema数据类型

    1.简单数据类型 (1)内置简单数据类型 schema中定义了一些简单数据类型,包括primitive原始数据类型和derived派生数据类型,这些类型都是schema中使用的 最基本的数据类型,我们 ...

  8. go语言-数据类型及类型之间转换

    数据类型分类 一.数据类型-基本数据类型 1.整数型(int.有符号(int8/1字节.int16/2字节.int32/4字节.int64/8字节).无符号(uint.uint8.uint16.uin ...

  9. golang 系列学习(-) 数据类型

    数据类型的出现 在的编程语言中,数据类型用于声明函数和变量,数据类型的出现是为了要把数据分成数据所需要内存大小的不同数据,编程时需要什么样的内存就申请什么样的内存.就可以充分的利用内存,更好的霸控程序 ...

随机推荐

  1. 递归--练习5--noi1751分解因数

    递归--练习5--noi1751分解因数 一.心得 想清楚子问题 想清楚递推表达式 没有全部AC说明还有自己没有想到的位置,试边界情况和查看题目要求 二.题目 1751:分解因数 总时间限制:  10 ...

  2. python学习笔记(HTMLTestRunner在Py3的兼容)

    博主最近开始重构自动化框架并且向Py3上兼容 第一个问题就是生成测试报告的HTMLTestRunner,由于此模块是基于Py2开发的,这里需要修改源码 # 94行 # import StringIO ...

  3. SQL Server 跨服务器 不同数据库之间复制表的数据

    不同数据库之间复制表的数据的方法: 当表目标表存在时: insert into 目的数据库..表 select * from 源数据库..表 当目标表不存在时: select * into 目的数据库 ...

  4. 移动前端兼容性笔记 - 安卓2.x 自带原生浏览器箭头问题

    这样的箭头用CSS-3实现,整段代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta c ...

  5. 浅析parseInt与parseFloat的区别

    parsetInt与parseFloat的区别还是很大的,简单来说,parseInt解析字符串为整数,parseFloat解析字符串为小数. 首先说parseInt() 1.可以接受两个参数,第一个为 ...

  6. HDU 1495 非常可乐 bfs 难度:1

    http://acm.hdu.edu.cn/showproblem.php?pid=1495 第三个杯子的盛水量可由前两个杯子得到,而前两个杯子状态总数在100*100以内,穷举可实现 #includ ...

  7. 简单使用dom4j

    package com.dom4j; import java.io.FileWriter; import java.io.IOException; import java.io.Unsupported ...

  8. 2017年7月ROS学习资料小结

    <孙子兵法·谋攻篇>:"上兵伐谋,其次伐交,其次伐兵,其下攻城:攻城之法为不得已." 任何发生在自己国土上的战争,即便胜利,也饱含屈辱. ----~~~~----Gaz ...

  9. 让黑白的SecureCRT彩色起来

    让黑白的SecureCRT彩色起来,如图仿真设置如下:  

  10. Julia 语言的一些尝试

    前些天发现了Julia 这门编程语言后便决定对其进行一些尝试,便写了下面的小程序,也算是看看这门语言所谓的速度快到底是怎么快法. 整数累加: x= function fff() : global x ...