mpi冒泡排序并行化

一、实验目的与实验要求

1、实验目的

(1)学会将串行程序改为并行程序。

(2)学会mpich2的使用。

(3)学会openmp的配置。

(4)mpi与openmp之间的比较。

2、实验要求

(1)将串行冒泡程序局部并行化,以降低时间消耗。

(2) 理论上求出时间复杂度之比,根据结果得出时间消耗之比,进行比对分析。

二、实验设备(环境)及要求

Vs2013,mpich2

三、实验内容与步骤

1、实验一 mpi并行

(1)实验内容

1、写出一个冒泡排序程序,求出其时间复杂度,并运行得到相应的时间消耗。

2、将冒泡程序改为mpi并行程序:将全部需要排序的数分成4等份,分给四个进程一起冒泡,最后将所得的结果归到一个进程,进行归并排序,得到结果,得到时间消耗。算出时间复杂度。

3、对得出的结果进行讨论与分析。

(2)主要步骤

1、串行冒泡程序

时间复杂度:取所要排序的数的个数为n个,时间复杂度为n*n/2。

代码实现:

// maopao.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"

#include "stdlib.h"

#include"time.h"

const int ARRAY_SIZE = 120000;

int main(int argc, char* argv[])

{

int zongshu[ARRAY_SIZE];

srand(10086);

time_t now_time, end_time;

for (int i = 0; i < ARRAY_SIZE; i++){

zongshu[i]=rand();

}

now_time = time(NULL);

for (int i = 0; i < ARRAY_SIZE; i++)

{

for (int j = ARRAY_SIZE - 1; j > i; j--)

{

if (zongshu[j] <= zongshu[j - 1])

{

int z = zongshu[j - 1];

zongshu[j - 1] = zongshu[j];

zongshu[j] = z;

}

}

}

end_time = time(NULL);

long shijian = end_time - now_time;

for (int i = 0; i <ARRAY_SIZE; i++){

printf("%d ", zongshu[i]);

}

printf("所用时间:%ld",shijian);

while (true);

}

2、并行程序

时间复杂度:取所要排序的数的个数为n个,进程数为m个。时间复杂度:((n/m)*(n/m)/2)+n+4*n。

代码实现:

// MPITest.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"

#include "mpi.h"

#include <stdio.h>

#include <math.h>

#include "stdlib.h"

#define SIZE 4//进程数

const int ARRAY_SIZE = 30000;//每个进程分配的个数

int shuzu[SIZE][ARRAY_SIZE];

int zonghanshu[SIZE][ARRAY_SIZE];

double endwtime;

void Scatter_1(int);

int main(int argc, char *argv[]){

int myid;

MPI_Init(&argc, &argv);

MPI_Comm_rank(MPI_COMM_WORLD, &myid);

Scatter_1(myid);

MPI_Finalize();

}

void Scatter_1(int myid){

int numtasks;

srand(10086);

for (int i = 0; i < SIZE; i++){

for (int j = 0; j < ARRAY_SIZE; j++){

shuzu[i][j] = rand();

}

}

//随机生成数组

int xiaopaixu[ARRAY_SIZE];

double startwtime = MPI_Wtime();

MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

if (numtasks == SIZE){

MPI_Scatter(shuzu, ARRAY_SIZE, MPI_INT, xiaopaixu, ARRAY_SIZE, MPI_INT, 0, MPI_COMM_WORLD);

for (int i = 0; i <ARRAY_SIZE; i++){

for (int j = ARRAY_SIZE - 1; j > i; j--){

if (xiaopaixu[j] <= xiaopaixu[j - 1]){

int z = xiaopaixu[j - 1];

xiaopaixu[j - 1] = xiaopaixu[j];

xiaopaixu[j] = z;

}

}

}//每个进程里的冒泡排序

MPI_Gather(xiaopaixu, ARRAY_SIZE, MPI_INT, zonghanshu, ARRAY_SIZE, MPI_INT, 0, MPI_COMM_WORLD);

int time[SIZE];

for (int i = 0; i < SIZE; i++){

time[i] = 0;

}

int a[SIZE];

int zongpaixu2[ARRAY_SIZE*SIZE];

for (int j = ARRAY_SIZE*SIZE - 1; j >= 0; j--){

for (int k = 0; k < SIZE; k++){

if (time[k] >= ARRAY_SIZE){

a[k] = 0;

}

else

{

a[k] = zonghanshu[k][ARRAY_SIZE - time[k] - 1];

}

}

int x = a[0];

for (int i = 1; i<SIZE; i++){

if (a[i]>x){

x = a[i];

}

}

for (int n = 0; n < SIZE; n++){

if (x == a[n]){

time[n] = time[n] + 1;

break;

}

}

zongpaixu2[j] = x;

}

endwtime = MPI_Wtime();

if (myid);

else

for (int i = 0; i < SIZE*ARRAY_SIZE; i++){

printf("%d ", zongpaixu2[i]);

}

}

if (myid);

else

printf("wall clock time=% f\n", endwtime - startwtime);

}

2、实验2

在实验一的基础上将程序改为openmp。

代码实现:(水平不高,写的程序通用性不好,只写了四线程的)

// Openmp.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"

#include <stdio.h>

#include <math.h>

#include "stdlib.h"

#include"time.h"

#include <omp.h>

#define SIZE 4

const int ARRAY_SIZE = 12000;

int shuzu[SIZE][ARRAY_SIZE];

int xiaopaixu1[ARRAY_SIZE];

int xiaopaixu2[ARRAY_SIZE];

int xiaopaixu3[ARRAY_SIZE];

int xiaopaixu4[ARRAY_SIZE];

int zonghanshu[SIZE][ARRAY_SIZE];

int zongpaixu[ARRAY_SIZE*SIZE];

void xiaohansu(int *A, int l, int u){

for (int i = l; i <u; i++){

for (int j = u - 1; j > i; j--){

if (A[j] <= A[j - 1]){

int z = A[j - 1];

A[j - 1] = A[j];

A[j] = z;

}

}

}

}

//每个线程排序

int main(int argc, char* argv[])

{

int t1, t2;

int i;

int id;

clock_t now_time, end_time;

srand(10086);

for (int i = 0; i < SIZE; i++){

for (int j = 0; j < ARRAY_SIZE; j++){

shuzu[i][j] = rand();

}

}

//随机生成数组

now_time = clock();

#pragma omp parallel default(none) shared(shuzu,xiaopaixu1,xiaopaixu2,xiaopaixu3,xiaopaixu4,ARRAY_SIZE) private(i)

{

#pragma omp for

for (i = 0; i < ARRAY_SIZE; i++)//这个for循环是并行的,将数组分为四份

{

xiaopaixu1[i] = shuzu[0][i];

xiaopaixu2[i] = shuzu[1][i];

xiaopaixu3[i] = shuzu[2][i];

xiaopaixu4[i] = shuzu[3][i];

}

}

#pragma omp parallel default(none) shared(xiaopaixu1,xiaopaixu2,xiaopaixu3,xiaopaixu4,ARRAY_SIZE)

{

#pragma omp parallel sections

{

#pragma omp section

xiaohansu(xiaopaixu1, 0, ARRAY_SIZE-1);//排序

#pragma omp section

xiaohansu(xiaopaixu2, 0, ARRAY_SIZE);

#pragma omp section

xiaohansu(xiaopaixu3, 0, ARRAY_SIZE);

#pragma omp section

xiaohansu(xiaopaixu4, 0, ARRAY_SIZE);

}

}

for (i = 0; i < ARRAY_SIZE; i++)//合到一份

{

zonghanshu[0][i]=xiaopaixu1[i];

zonghanshu[1][i]=xiaopaixu2[i];

zonghanshu[2][i]=xiaopaixu3[i];

zonghanshu[3][i]=xiaopaixu4[i];

}

int time[SIZE];

for (int i = 0; i < SIZE; i++){

time[i] = 0;

}

int a[SIZE];

for (int j = ARRAY_SIZE*SIZE - 1; j >= 0; j--){

for (int k = 0; k < SIZE; k++){

if (time[k] >= ARRAY_SIZE){

a[k] = 0;

}

else

{

a[k] = zonghanshu[k][ARRAY_SIZE - time[k] - 1];

}

}

int x = a[0];

for (int i = 1; i<SIZE; i++){

if (a[i]>x){

x = a[i];

}

}

for (int n = 0; n < SIZE; n++){

if (x == a[n]){

time[n] = time[n] + 1;

break;

}

}

zongpaixu[j] = x;

}

//归并

end_time = clock();

double shijian = end_time - now_time;

for (int i = 0; i <SIZE*ARRAY_SIZE; i++){

printf("%d ", zongpaixu[i]);

}

printf("所用时间:%lf", shijian / CLK_TCK);

while (true);

}

四:实验结果与分析

Mpi:

串行

Mpi


 


 1.2


 2.4


 3.6


 4.8


 6.0


 7.2


串行(秒)


0.441


1.766


3.951


6.877


10.469


14.687


6线(秒)


0.029


0.108


0.242


0.435


0.656


0.940


4线(秒)


0.035


0.151


0.339


0.615


0.969


1.409


2线(秒)


0.119


0.502


1.108


2.040


3.121


4.516

从表中可以看出4线程的时候,并行程序的速度是串行程序速度的十倍之多,而理论上大概8倍。这就跟改的程序有关。在并行程序中,最后采用的是归并,由此,发生了这些奇妙的情况:实则本身的算法就比冒泡优一些,但又不能只采用冒泡算法,那样在最后又来个冒泡,其程序就没有意义了。

Openmp

这是4.8万个数排序的结果,可以看出用了2.876秒,比MPI慢了四倍之多,这可能是程序的不合理,带来了多余的时间消耗(通信)。但比串行还是要快很多。

五:结论(讨论)

1、实验结论

1、就这冒泡排序改为并行的,虽然时间缩短了很多倍,但与快排等排序算法并行相比,其速度又不堪入目。

2、就冒泡排序而言,其mpi并行远远优于openmp(就我写的程序而言。。。),虽然最后都用了并归。

2、讨论

1、这些程序都实现在一台电脑上完成的,还未试过与其他电脑通信,所以其所表现出来的结果并不完全按正确,毕竟并行计算涉及到不同主机之间的通信。

2、由于个人编程能力不高,在这里只讨论了一些时间上的差异,并未对空间上进行比对(不会。。。)。

3、就openmp程序而言,应该还可以改写,增加其通用性和减少通信。

时间: 2024-10-12 23:43:01

mpi冒泡排序并行化的相关文章

Floyd-Warshall算法及其并行化实现(基于MPI)

Floyd-Warshall算法(或称Floyd算法)是用于寻找加权图中非固定起止点间最短路径的经典算法,它是基于动态规划思想设计的.当前我们所认识的Floyd算法之形式由计算机科学家(同时也是图灵奖得主) Robert Floyd 于 1962 年提出并发表.但在此之前,Bernard Roy(1959)和 Stephen Warshall(1962)也分别独立地提出了类似的算法.本文将主要讨论基于MPI的并行化Floyd算法实现. 欢迎关注白马负金羁的博客 http://blog.csdn.

什么是代码现代化?

By Mike P. (Intel), Added 2015 年 7 月 8 日 现代高性能计算机由下列资源组合构建而成:多核处理器.众核处理器.大型高速缓存,高带宽进程间通信结构和高速 I/O 功能. 高性能软件需经过设计,以充分利用这些丰富的资源. 无论是重新构建并/或调优现有应用以发挥最高性能,或为现有或未来设备构建新应用,了解编程模型和高效利用资源之间的相互作用极其关键. 以此为起点,全面了解代码现代化. 关于性能,您的代码至关重要! 构建软件的并行版本可使应用在更短的时间内运行指定的数

连通域标记算法并行化(MPI+OpenMP)

1 背景 图像连通域标记算法是从一幅栅格图像(通常为二值图像)中,将互相邻接(4邻接或8邻接)的具有非背景值的像素集合提取出来,为不同的连通域填入数字标记,并且统计连通域的数目.通过对栅格图像中进行连通域标记,可用于静态地分析各连通域斑块的分布,或动态地分析这些斑块随时间的集聚或离散,是图像处理非常基础的算法.目前常用的连通域标记算法有1)扫描法(二次扫描法.单向反复扫描法等).2)线标记法.3)区域增长法.二次扫描法由于简单通用而被广泛使用! 图1 连通域标记示意图 随着所要处理的数据量越来越

使用 MPI for Python 并行化遗传算法

前言 本文中作者使用MPI的Python接口mpi4py来将自己的遗传算法框架GAFT进行多进程并行加速.并对加速效果进行了简单测试. 项目链接: GitHub: https://github.com/PytLab/gaft PyPI: https://pypi.python.org/pypi/gaft 正文 我们在用遗传算法优化目标函数的时候,函数通常都是高维函数,其导数一般比较难求取.这样我们的适应度函数计算通常都是比较费时的计算. 例如在使用遗传算法寻找最优结构时候通常需要调用量化软件进行

MPI编程简单介绍

第三章MPI编程 3.1 MPI简单介绍 多线程是一种便捷的模型,当中每一个线程都能够訪问其他线程的存储空间.因此,这样的模型仅仅能在共享存储系统之间移植.一般来讲,并行机不一定在各处理器之间共享存储,当面向非共享存储系统开发并行程序时,程序的各部分之间通过来回传递消息的方式通信.要使得消息传递方式可移植,就须要採用标准的消息传递库.这就促成的消息传递接口(Message Passing Interface, MPI)的面世,MPI是一种被广泛採用的消息传递标准[1]. 与OpenMP并行程序不

OpenMp实现并行化

前言 昨天,往arm上移植opencv程序,发现运行速度很慢.观察资源监视器发现只有一个核处于高负荷(总共4核),遂考虑到需要多核计算.OpenMp和MPI是常用并行计算库,OpenMP相对简单适合单机多核多线程,MPI适合集群,但复杂. OpenMp是由OpenMP Architecture Review Board牵头提出的,并已被广泛接受的,用于共享内存并行系统的多处理器程序设计的一套指导性的编译处理方案(Compiler Directive).OpenMP支持的编程语言包括C语言.C++

【LDA】用MPI优化GibbsLDA++-0.2

MPI 是"Message Passing Interface"的缩写,通常用来做单机多线程的并发编程. 1. GibbsLDA++中训练框架大致如下: 循环:训练过程迭代N次 { 循环:遍历每一个训练样本(指doc) { 循环:遍历训练样本中的每一个word { 循环:gibbs采样过程,遍历每一个topic { 会更新: doc-topic矩阵. word-topic矩阵. doc-topic的边缘分布向量. word-topic的边缘分布向量 当前word在topic上的分布向量

【并行计算】用MPI进行分布式内存编程(二)

通过上一篇中,知道了基本的MPI编写并行程序,最后的例子中,让使用0号进程做全局的求和的所有工作,而其他的进程却都不工作,这种方式也许是某种特定情况下的方案,但明显不是最好的方案.举个例子,如果我们让偶数号的进程负责收集求和的工作,情况会怎么样?如下图: 对比之前的图发现,总的工作量与之前的一样,但是发现新方案中0号进程只做了3次接收和3次加法(之前的7次接收和7次加法),如果进程都是同时启动的,那么全局求和时间将是0号进程的接收时间和求和时间,即需要的总时间比原来方案的总时间减少了50%多.如

【深度学习系列4】深度学习及并行化实现概述

[深度学习系列4]深度学习及并行化实现概述 摘要: 深度学习可以完成需要高度抽象特征的人工智能任务,如语音识别.图像识别和检索.自然语言理解等.深层模型是包含多个隐藏层的人工神经网络,多层非线性结构使其具备强大的特征表达能力和对复杂任务建模能力.训练深层模型是长期以来的难题,近年来以层次化.逐层初始化为代表的一系列方法的提出给训练深层模型带来了希望,并在多个应用领域获得了成功.深层模型的并行化框架和训练加速方法是深度学习走向实用的重要基石,已有多个针对不同深度模型的开源实现,Google.Fac