MPI实现并行奇偶排序
奇偶排序
odd-even-sort, using MPI
代码在 https://github.com/thkkk/odd-even-sort
使用 MPI 实现奇偶排序算法, 并且 MPI 进程 只能向其相邻进程发送消息
nprocs 是进程数。 每个进程拥有独立的一块数据 data[0 ~ block_len-1],组合起来为整个待排序的数组。
方法
每个阶段排序之后不进行check
此前,在每个阶段的奇偶排序进行完之后,都会进行一次进程之间的信息传递,以判断排序是否完成,这个过程要进行约\(3*nprocs\)次的send/recv。现在的优化是:总共只进行nprocs轮排序,不再进行check。这样的话,即使是目前在最小编号进程中的元素,而它值较大,本应排序到最大编号进程中,也可以在nprocs轮中排到正确的位置。
这样之后,大约有几十ms的优化。
进程之间互相传递数据,然后进行优化后的归并
在一个排序阶段中,相邻进程块互相发送自己的全部数据,之后在每个块内部将两个块的数据进行归并,但是只保留最小/最大的block_len个元素,将其拷贝到自己的data上。这样可以省掉一半的归并时间。
这样之后大约有100+ms的优化。
进程之间发送全部数据之前,先发送端点处的数据
进程之间发送全部数据之前,先发送端点处的数据,判断左边进程中的最大元素是否小于等于右边进程中的最小元素,如果是,那么无需进行后续数据的发送和归并。
这样之后大约有几十ms的优化。
代码
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <mpi.h>
#include <cmath>
#include "worker.h"
using namespace std;
bool is_edge(int rank, bool odd_or_even, bool last_rank){
if (odd_or_even == 0){
return (rank & 1) == 0 && last_rank;
}
else{
return rank == 0 || ((rank & 1) == 1 && last_rank);
}
}
void merge_left(float *A, int nA, float *B, int nB, float *C){ //make sure C[nA-1] is available
float *p1 = A, *A_end = A + nA, *p2 = B, *B_end = B + nB, *p = C, *C_end = C + nA;
while( p != C_end && p1 != A_end && p2 != B_end)
*(p++) = ((*p1) <= (*p2)) ? *(p1++) : *(p2++);
while( p != C_end )
*(p++) = *(p1++);
}
void merge_right(float *A, int nA, float *B, int nB, float *C){
float *p1 = A + nA , *p2 = B + nB , *p = C + nB;
while( p != C && p1 != A && p2 != B )
*(--p) = (*(p1-1) >= *(p2-1)) ? *(--p1) : *(--p2);
while( p != C )
*(--p) = *(--p2);
}
void Worker::sort() {
//data[0, block_len)
if (out_of_range) return ;
std::sort(data, data + block_len);
//先把当前进程数据排好序
if (nprocs == 1) return ;
bool odd_or_even = 0; // = 0: even; = 1: odd;
float *cp_data = new float [block_len];
float *adj_data = new float [ceiling(n, nprocs)];
int limit = nprocs;
while(limit--){
if(is_edge(rank, odd_or_even, last_rank)){
//边界情况,没有与其他进程存在于同一个进程块内
}
else if((rank & 1) == odd_or_even){ //receive info
size_t adj_block_len = std::min(block_len, n - (rank + 1) * block_len);
MPI_Request request[2];
MPI_Isend(data + block_len - 1, 1, MPI_FLOAT, rank + 1, 0, MPI_COMM_WORLD, &request[0]);
MPI_Irecv(adj_data, 1, MPI_FLOAT, rank + 1, 1, MPI_COMM_WORLD, &request[1]);
MPI_Wait(&request[0], MPI_STATUS_IGNORE);
MPI_Wait(&request[1], MPI_STATUS_IGNORE); //发送端点数据
if(data [block_len - 1] > adj_data[0]) {
//此时两块之间存在未排好序的数据,需要排序
MPI_Sendrecv(data, block_len, MPI_FLOAT, rank + 1, 0,
adj_data, adj_block_len, MPI_FLOAT, rank + 1, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
//互相交换数据
// merge
merge_left(data, (int)block_len, adj_data, (int)adj_block_len, cp_data);
//进行归并排序,取前block_len个数据返回到cp_data中
memcpy(data, cp_data, block_len * sizeof(float)); //拷贝回data
}
}
else if ((rank & 1) == !odd_or_even){ //send info
size_t adj_block_len = ceiling(n, nprocs);
MPI_Request request[2];
MPI_Isend(data, 1, MPI_FLOAT, rank - 1, 1, MPI_COMM_WORLD, &request[1]);
MPI_Irecv(adj_data + adj_block_len - 1, 1, MPI_FLOAT, rank
- 1, 0, MPI_COMM_WORLD, &request[0]);
MPI_Wait(&request[1], MPI_STATUS_IGNORE);
MPI_Wait(&request[0], MPI_STATUS_IGNORE);
//发送端点数据
if (adj_data[adj_block_len - 1] > data[0]){
//此时两块之间存在未排好序的数据,需要排序
MPI_Sendrecv(data, block_len, MPI_FLOAT, rank - 1, 1,
adj_data, adj_block_len, MPI_FLOAT, rank - 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
//互相交换数据
// merge
merge_right(adj_data, (int)adj_block_len, data, (int)block_len, cp_data);
//进行归并排序,取前block_len个数据返回到cp_data中
memcpy(data, cp_data, block_len * sizeof(float)); //拷贝回data
}
}
odd_or_even ^= 1;
}
delete[] cp_data;
delete[] adj_data;
}
实验数据
| n | N\(\times\) P | 耗时(ms) | 相对单进程的加速比 |
|---|---|---|---|
| 100000000 | 1$\times$1 | 12728.326000 | 1 |
| 100000000 | 1$\times$2 | 6754.229000 | 1.884 |
| 100000000 | 1$\times$4 | 3559.514000 | 3.576 |
| 100000000 | 1$\times$8 | 2007.818000 | 6.339 |
| 100000000 | 1$\times$16 | 1340.771000 | 9.493 |
| 100000000 | 2$\times$16 | 870.302000 | 14.625 |
MPI实现并行奇偶排序的更多相关文章
- 【MPI】并行奇偶交换排序
typedef long long __int64; #include "mpi.h" #include <cstdio> #include <algorithm ...
- Hark的数据结构与算法练习之奇偶排序
算法说明 奇偶排序又叫奇偶换位排序,砖排序.它是一种交换排序,也是冒泡的一个变种 顾名思义,奇偶排序,其实就是先循环奇数位,然后将奇数位与偶数位比较计算. 然后再循环偶数位,再和奇数位比较运算.看一下 ...
- OpenJudge计算概论-整数奇偶排序
/*===================================== 整数奇偶排序 总时间限制: 1000ms 内存限制: 65536kB 描述 输入10个整数,彼此以空格分隔 重新排序以后 ...
- 排序算法之奇偶排序 JAVA奇偶排序算法
奇偶排序法的思路是在数组中重复两趟扫描.第一趟扫描选择所有的数据项对,a[j]和a[j+1],j是奇数(j=1, 3, 5……).如果它们的关键字的值次序颠倒,就交换它们.第二趟扫描对所有的偶数数据项 ...
- Openjudge-计算概论(A)-整数奇偶排序
描述: 输入10个整数,彼此以空格分隔重新排序以后输出(也按空格分隔),要求:1.先输出其中的奇数,并按从大到小排列:2.然后输出其中的偶数,并按从小到大排列.输入任意排序的10个整数(0-100), ...
- LeetCode905.按奇偶排序数组
905.按奇偶排序数组 问题描述 给定一个非负整数数组 A,返回一个由 A 的所有偶数元素组成的数组,后面跟 A 的所有奇数元素. 你可以返回满足此条件的任何数组作为答案. 示例 输入:[3,1,2, ...
- OpenJudge计算概论-奇偶排序
/*==============================================总时间限制: 1000ms 内存限制: 65536kB描述 输入十个整数,将十个整数按升序排列输出,并且 ...
- P1021 整数奇偶排序
整数奇偶排序 题目出处:<信息学奥赛一本通>第二章上机练习6,略有改编 题目描述 告诉你包含 \(n\) 个数的数组 \(a\) ,你需要把他们按照"奇数排前面,偶数排后面:奇数 ...
- 每日一题20201112(922. 按奇偶排序数组 II)
题目链接: 922. 按奇偶排序数组 II 思路 很简单,搞懂问题的核心就行,假设现在有奇数在偶数位上,偶数在奇数位上. 那么我们要做的就是,找到分别在对方位置上的数字,然后交换他们就行. class ...
随机推荐
- 承上启下继往开来,Python3上下文管理器(ContextManagers)与With关键字的迷思
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_217 在开发过程中,我们会经常面临的一个常见问题是如何正确管理外部资源,比如数据库.锁或者网络连接.稍不留意,程序将永久保留这些资 ...
- 网络编程、OSI七层协议
目录 软件开发架构 1.什么是软件开发架构 2.软件开发架构 3.架构优劣势 4.架构发展趋势 网络编程简介 1.如何理解网络编程 2.网络编程的目的 3.网络编程的意义 4.网络编程的起源 5.网络 ...
- MYSQL(进阶篇)——一篇文章带你深入掌握MYSQL
MYSQL(进阶篇)--一篇文章带你深入掌握MYSQL 我们在上篇文章中已经学习了MYSQL的基本语法和概念 在这篇文章中我们将讲解底层结构和一些新的语法帮助你更好的运用MYSQL 温馨提醒:该文章大 ...
- 针对多个球体的World类
World类其他都一样的,就修改build函数就行了,以后测试所有代码,都是基于两个或多个球体的,不再重复阐述. void World::build() { vp.set_hres(200); vp. ...
- doc或docx(word)或image类型文件批量转PDF脚本
doc或docx(word)或image类型文件批量转PDF脚本 1.实际生产环境中遇到文件展示只能适配PDF版本的文件,奈何一万个文件有七千个都是word或者image类型的,由此搞个脚本批量转换下 ...
- flutter系列之:构建Widget的上下文环境BuildContext详解
目录 简介 BuildContext的本质 BuildContext和InheritedWidget BuildContext的层级关系 总结 简介 我们知道Flutter中有两种Widget,分别是 ...
- 分布式版本控制系统Git的使用;
1.什么是Git Git是一个分布式的版本控制软件: 软件,类似于qq.office等安装到电脑才能使用的工具. 版本控制,类似于毕业论文,视频剪辑等需要反复修改和保留原历史数据: 分布式 文件夹拷贝 ...
- 《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(16)-Fiddler如何充当第三者,再识AutoResponder标签-上篇
1.简介 Fiddler充当第三者,主要是通过AutoResponder标签在客户端和服务端之间,Fiddler抓包,然后改包,最后发送.AutoResponder这个功能可以算的上是Fiddler最 ...
- awk5个使用场景
awk简介 首先要知道awk的使用场景,需了解awk有哪些优势与短板. 关于个人近期学习awk总结其优势: awk对文本的处理运算效率同比其他工具效率高很多(比shell的for循环高10倍以上,运算 ...
- KingbaseES Truncate 与 Delete 机制比较
使用过Oracle的都知道,Truncate操作由于不需要写redo日志,因此,在性能上会比delete操作更高效,但在实际使用过程中,有时会发现delete比truncate速度更快.以下介绍下二者 ...