一、实验目的与实验要求

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"

;

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

{

    int zongshu[ARRAY_SIZE];

    srand();

    time_t now_time, end_time;

    ; i < ARRAY_SIZE; i++){

        zongshu[i]=rand();

    }

    now_time = time(NULL);

    ; i < ARRAY_SIZE; i++)

    {

        ; j > i; j--)

        {

            ])

            {

                ];

                zongshu[j - ] = zongshu[j];

                zongshu[j] = z;

            }

        }  

    }

    end_time = time(NULL);

    long shijian = end_time - now_time;

    ; 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//进程数

;//每个进程分配的个数

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();

    ; i < SIZE; i++){

        ; 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, , MPI_COMM_WORLD);

        ; i <ARRAY_SIZE; i++){

            ; j > i; j--){

                ]){

                    ];

                    xiaopaixu[j - ] = xiaopaixu[j];

                    xiaopaixu[j] = z;

                }

            }

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

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

        int time[SIZE];

        ; i < SIZE; i++){

            time[i] = ;

        }

        int a[SIZE];

        int zongpaixu2[ARRAY_SIZE*SIZE];

        ; j >= ; j--){

            ; k < SIZE; k++){

                if (time[k] >= ARRAY_SIZE){

                    a[k] = ;

                }

                else

                {

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

                }

            }

            ];

            ; i<SIZE; i++){

                if (a[i]>x){

                    x = a[i];

                }

            }

            ; n < SIZE; n++){

                if (x == a[n]){

                    time[n] = time[n] + ;

                    break;

                }

            }

            zongpaixu2[j] = x;

        }

        endwtime = MPI_Wtime();

        if (myid);

        else

        ; 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

;

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++){

        ; j > i; j--){

            ]){

                ];

                A[j - ] = 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();

    ; i < SIZE; i++){

        ; 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 

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

        {

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

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

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

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

        }

    }

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

    {

#pragma omp parallel sections 

        {

#pragma omp section 

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

#pragma omp section 

            xiaohansu(xiaopaixu2, , ARRAY_SIZE);

#pragma omp section 

            xiaohansu(xiaopaixu3, , ARRAY_SIZE);

#pragma omp section 

            xiaohansu(xiaopaixu4, , ARRAY_SIZE);      

        }

    }

; i < ARRAY_SIZE; i++)//合到一份

    {

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

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

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

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

    }

int time[SIZE];

    ; i < SIZE; i++){

        time[i] = ;

    }

    int a[SIZE];

    ; j >= ; j--){

        ; k < SIZE; k++){

            if (time[k] >= ARRAY_SIZE){

                a[k] = ;

            }

            else

            {

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

            }

        }

        ];

        ; i<SIZE; i++){

            if (a[i]>x){

                x = a[i];

            }

        }

        ; n < SIZE; n++){

            if (x == a[n]){

                time[n] = time[n] + ;

                break;

            }

        }

        zongpaixu[j] = x;

    }

//归并

end_time = clock();

double shijian = end_time - now_time;

; 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程序而言,应该还可以改写,增加其通用性和减少通信。

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

  1. kmeans算法并行化的mpi程序

    用c语言写了kmeans算法的串行程序,再用mpi来写并行版的,貌似参照着串行版来写并行版,效果不是很赏心悦目~ 并行化思路: 使用主从模式.由一个节点充当主节点负责数据的划分与分配,其他节点完成本地 ...

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

    前言 本文中作者使用MPI的Python接口mpi4py来将自己的遗传算法框架GAFT进行多进程并行加速.并对加速效果进行了简单测试. 项目链接: GitHub: https://github.com ...

  3. 方阵行列式并行化计算(OpenMP,MPI),并计算加速比

    00][100].在创建方阵时,方阵的阶数N(N<100)由外部输入.然后用两层"for循环"来给方阵 p左上角 N×N个位置赋值.具体实现如下: /* * 定义矩阵阶数N ...

  4. 大数据并行计算利器之MPI/OpenMP

    大数据集群计算利器之MPI/OpenMP ---以连通域标记算法并行化为例 1 背景 图像连通域标记算法是从一幅栅格图像(通常为二值图像)中,将互相邻接(4邻接或8邻接)的具有非背景值的像素集合提取出 ...

  5. MPI编程简单介绍

    第三章MPI编程 3.1 MPI简单介绍 多线程是一种便捷的模型,当中每一个线程都能够訪问其他线程的存储空间.因此,这样的模型仅仅能在共享存储系统之间移植.一般来讲,并行机不一定在各处理器之间共享存储 ...

  6. MPI编程简述

    第三章MPI计划 3.1 MPI简单介绍 多线程是一种便捷的模型,当中每一个线程都能够訪问其他线程的存储空间.因此,这样的模型仅仅能在共享存储系统之间移植. 一般来讲,并行机不一定在各处理器之间共享存 ...

  7. mpi和cuda混合编程的正确编译

    针对大数据的计算,很多程序通过搭建mpi集群进行加速,并取得了很好的效果.算法内部的加速,当前的并行化趋势是利用GPU显卡进行算法加速.针对并行性非常好的算法,GPU加速效果将远大于集群带来的加速效果 ...

  8. MPI编程简介[转]

    原文地址http://blog.csdn.net/qinggebuyao/article/details/8059300 3.1 MPI简介 多线程是一种便捷的模型,其中每个线程都可以访问其它线程的存 ...

  9. win 10 在vs2017下对mpi的安装以及认识

    这里我先对MPI进行一下简单的介绍,MPI的全称是Message Passing Interface,即消息传递接口. 它并不是一门语言,而是一个库,我们可以用Fortran.C.C++结合MPI提供 ...

随机推荐

  1. css 笔记——设置禁用中文输入法

    ime-mode ime-mode的语法解释如下: ime-mode : auto | active | inactive | disabled 取值: auto  : 默认值.不影响IME的状态.与 ...

  2. Java使用wkhtmltox实现HTML代码生成PDF文档或者图片

    由于项目需要,把HTML代码转为PDF或者图片进行保存.最开始使用Flying Saucer来把HTML代码生成为PDF文档,功能已经开发出来了,也能够完成转换功能,期间也遇到了中文支持以及图片路径的 ...

  3. 第二节 hibernate session介绍以及session常用方法介绍

    原创地址:http://www.cnblogs.com/binyulan/p/5628579.html Session是java应用程序和hibernate框架之间的一个主要接口.它是从持久化服务中剥 ...

  4. js function定义函数的4种方法

    js function定义函数的4种方法 1.最基本的作为一个本本分分的函数声明使用. 复制代码代码如下: 复制代码代码如下: function func(){} 或 var func=functio ...

  5. Centos下如何修改Mysql的root密码

    1.用帐号登录mysql mysql –u root 或#mysql –uroot –p 2.改变用户数据库 命令:mysql>use mysql mysql> use mysqlRead ...

  6. Qt移植 Window --Linux

    1.把源代码复制到Linux目录,使用qmake命令,注意在shell中直接使用qmake命令注意设置PATH环境变量 2. 在目录中会生成Makeflie文件 3. make即可 /usr/bin/ ...

  7. 发送邮件(遵循smtp协议即简单的邮件发送协议)

    HandleSendEmail.aspx逻辑 protected void Page_Load(object sender,EventArgs e) { foreach(var item in Req ...

  8. DISCUZ! X2.5设置仅允许QQ登录注册论坛 加固会员注册机制

    论坛稍微有点起色之后,很多站长就会担心论坛经常被人恶意灌水.注册机.顶贴机等等一些列非法的手段.通常站长都会通过一些后台的设置和插件等等一 切有效的方法预防,但更多的站长会通过限制用户注册会员,需注册 ...

  9. iphone开发第二个程序

    此程序包括UIProgressView,UIButton, UIDatePicker,UIAlert,UILabel,NSTimer // //  HViewController.h //  Btn_ ...

  10. 解决pxe网络批量安装部署linux遇到的问题和解决方法

    解决“出现Unable to retrieve 192.168.0.100/var/www/html/images/install.img错误” 分析:我们必须了解这个错误出现在哪个阶段才能正确找到错 ...