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。

代碼實現:

#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。

   代碼實現:(水平不高,寫的程序通用性不好,只寫了四線程的)

#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程序而言,應該還可以改寫,增加其通用性和減少通信。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM