在多核处理器、超级计算机日益普及的今天,程序员们怎能对并行程序“袖手旁观”呢?

为了练手,我用MPI写了一个并行排序程序,

先介绍下我的第一个版本,大概的思路是:

使用MPI在各个进程之间进行通信,

1. 进程0生成随机数,并且讲数据分段,将各段数据分配给其他进程

2. 其他进程收到数据段,使用冒泡排序进行,发送回进程0

3. 进程0收到这些数据,通过归并排序按顺序整合起来。

下面是这个版本代码,

View Code

// MPI Hello World demo#include <mpi.h>#include <stdio.h>#include <stdlib.h>#include <time.h>#define N 30

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

int processRank, processNum, t, data, num;int dataArr[N];int dataArrB[N];int pointer[100];int secEnd[100];

    MPI_Status mpistat;    MPI_Init(&argc, &argv);    MPI_Comm_size(MPI_COMM_WORLD, &processNum);    MPI_Comm_rank(MPI_COMM_WORLD, &processRank);

    printf("Yes, Sir!\nFrom process %i of %i\n", processRank, processNum);if(processRank == 0)     {        srand(time(NULL));

for (int i = 0; i < N; i++){            dataArr[i] = rand()%1000;        }        printf("Original Array:\n");for (int i = 0; i< N; i++){            printf("%d ", dataArr[i]);        }        printf("\n");        puts("Distribute data to processes");for (int i = 1; i < processNum; i++){            num = (N/(processNum-1));if (i == processNum -1)                num = N - num * (processNum -2);///distribute data to each process            printf("Sending to process %d...\n", i);            MPI_Send(&num, 1, MPI_INT, i, 55, MPI_COMM_WORLD);            MPI_Send(&dataArr[(N/(processNum-1)) * (i-1)], num, MPI_INT, i, 55, MPI_COMM_WORLD);///gather the sorted data            printf("Receiving from process %d...\n", i);            MPI_Recv(&dataArrB[(N/(processNum-1)) * (i-1)], num, MPI_INT, i, 55, MPI_COMM_WORLD, &mpistat);///prepare for merge, set the pointers            pointer[i] = (N/(processNum-1)) * (i-1);            secEnd[i] = pointer[i] + N/(processNum-1);if (i == processNum-1 ) secEnd[i] = N;        }        printf("Sorted Sections Array:\n");for (int i = 0; i< N; i++){            printf("%d ", dataArrB[i]);        }        puts("");///merge the sorted sections        puts("Merging...");for (int i = 0; i < N; i++){int tMin = 1;int min = 10000;for (t = 1; t < processNum; t++){if (pointer[t] < secEnd[t] && dataArrB[pointer[t]] < min){                    min = dataArrB[pointer[t]];                    tMin = t;                }            }            dataArr[i] = dataArrB[pointer[tMin]];            pointer[tMin]++;        }///output the results        printf("Final Sorted Array:\n");for (int i = 0; i< N; i++){            printf("%d ", dataArr[i]);        }        printf("\n");    } else     {//receieve the section        MPI_Recv(&num, 1, MPI_INT, 0, 55, MPI_COMM_WORLD, &mpistat);        MPI_Recv(&dataArr[0], num, MPI_INT, 0, 55, MPI_COMM_WORLD, &mpistat);        printf("Received Original Array:\n");for (int i = 0; i< num; i++){            printf("%d ", dataArr[i]);        }        printf("\n");//sort this section        for (int i = 0; i < num -1; i++)for (int j = num-1; j>=i+1; j--)if (dataArr[j] < dataArr[j-1]){int tmp = dataArr[j];                    dataArr[j]= dataArr[j-1];                    dataArr[j-1] = tmp;                }        MPI_Send(&dataArr[0], num, MPI_INT, 0, 55, MPI_COMM_WORLD);///display        printf("My Sorted Section:\n");for (int i = 0; i< num; i++){            printf("%d ", dataArr[i]);        }        printf("\n");    }    MPI_Finalize();return 0;}

自己写出之后当然高兴,不过程序经过高手检查之后,提出了一些问题。

最要命的是这个

for (int i = 1; i < processNum; i++){            num = (N/(processNum-1));if (i == processNum -1)                num = N - num * (processNum -2);///distribute data to each process            printf("Sending to process %d...\n", i);            MPI_Send(&num, 1, MPI_INT, i, 55, MPI_COMM_WORLD);            MPI_Send(&dataArr[(N/(processNum-1)) * (i-1)], num, MPI_INT, i, 55, MPI_COMM_WORLD);///gather the sorted data            printf("Receiving from process %d...\n", i);            MPI_Recv(&dataArrB[(N/(processNum-1)) * (i-1)], num, MPI_INT, i, 55, MPI_COMM_WORLD, &mpistat);///prepare for merge, set the pointers            pointer[i] = (N/(processNum-1)) * (i-1);            secEnd[i] = pointer[i] + N/(processNum-1);if (i == processNum-1 ) secEnd[i] = N;        }

这段程序彻底抹杀掉了我这个并行程序的光辉形象,因为这段煞有介事的并行程序,其实是一段串行程序。

屏幕前的高手应该看出来了吧,同一段程序的收发,都在同一段循环中。

也就意味着,不同段之间的收发是一个接着一个的。也就意味着,其他每个进程各自的排序也是一个接着一个进行的,并不会如我初衷并行排序。

想来,这段错误应该是并行程序小白们常犯的错误,所以我也很乐于把我做过的蠢事发出来给大家分享。前车之鉴,警钟长鸣lol

改正之后的这段程序是这样的,

for (int i = 1; i < processNum; i++){            num = (N/(processNum-1));if (i == processNum -1)                num = N - num * (processNum -2);///distribute data to each process            printf("Sending to process %d...\n", i);            MPI_Send(&num, 1, MPI_INT, i, 55, MPI_COMM_WORLD);            MPI_Send(&dataArr[(N/(processNum-1)) * (i-1)], num, MPI_INT, i, 55, MPI_COMM_WORLD);                                }for (int i = 1; i < processNum; i++){            num = (N/(processNum-1));if (i == processNum -1)                num = N - num * (processNum -2);///gather the sorted data            printf("Receiving from process %d...\n", i);            MPI_Recv(&dataArrB[(N/(processNum-1)) * (i-1)], num, MPI_INT, i, 55, MPI_COMM_WORLD, &mpistat);///prepare for merge, set the pointers            pointer[i] = (N/(processNum-1)) * (i-1);            secEnd[i] = pointer[i] + N/(processNum-1);if (i == processNum-1 ) secEnd[i] = N;        }

同时程序的效率还可以提升,比如说把其他进程排序的算法换成快排什么的。

最后奉上优化后的版本,

View Code

// MPI Hello World demo#include <mpi.h>#include <stdio.h>#include <stdlib.h> // 'qsort' is in it.#include <time.h>#include <map>#define N 30

int QuickSortCompareFun(const void *p1, const void *p2){return *((const int*)p1) - *((const int*)p2);}

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

int processRank, processNum, t, data, num;int dataArr[N];int dataArrB[N];int pointer[100];int secEnd[100];

    MPI_Status mpistat;    MPI_Init(&argc, &argv);    MPI_Comm_size(MPI_COMM_WORLD, &processNum);    MPI_Comm_rank(MPI_COMM_WORLD, &processRank);

    printf("Yes, Sir!\nFrom process %i of %i\n", processRank, processNum);if(processRank == 0)     {        srand(time(NULL));

for (int i = 0; i < N; i++){            dataArr[i] = rand()%1000;        }        printf("Original Array:\n");for (int i = 0; i< N; i++){            printf("%d ", dataArr[i]);        }        printf("\n");        puts("Distribute data to processes");for (int i = 1; i < processNum; i++){            num = (N/(processNum-1));if (i == processNum -1)                num = N - num * (processNum -2);///distribute data to each process            printf("Sending to process %d...\n", i);            MPI_Send(&num, 1, MPI_INT, i, 55, MPI_COMM_WORLD);            MPI_Send(&dataArr[(N/(processNum-1)) * (i-1)], num, MPI_INT, i, 55, MPI_COMM_WORLD);                                }for (int i = 1; i < processNum; i++){            num = (N/(processNum-1));if (i == processNum -1)                num = N - num * (processNum -2);///gather the sorted data            printf("Receiving from process %d...\n", i);            MPI_Recv(&dataArrB[(N/(processNum-1)) * (i-1)], num, MPI_INT, i, 55, MPI_COMM_WORLD, &mpistat);///prepare for merge, set the pointers            pointer[i] = (N/(processNum-1)) * (i-1);            secEnd[i] = pointer[i] + N/(processNum-1);if (i == processNum-1 ) secEnd[i] = N;        }        printf("Sorted Sections Array:\n");for (int i = 0; i< N; i++){            printf("%d ", dataArrB[i]);        }        puts("");///merge the sorted sections        puts("Merging...");        std::map<int, int> data2rank;        for (t = 1; t < processNum; t++){if (pointer[t] < secEnd[t]){                data2rank.insert(std::make_pair<int, int>(dataArrB[pointer[t]], t));                pointer[t]++;            }        }for (int i = 0; i < N; i++){int data = data2rank.begin()->first;int rank = data2rank.begin()->second;            dataArr[i] = data;            data2rank.erase(data2rank.begin());if (pointer[rank] < secEnd[rank])            {                data2rank.insert(std::make_pair<int, int>(dataArrB[pointer[rank]], rank));                pointer[rank]++;            }        }///output the results        printf("Final Sorted Array:\n");for (int i = 0; i< N; i++){            printf("%d ", dataArr[i]);        }        printf("\n");    } else     {//receieve the section        MPI_Recv(&num, 1, MPI_INT, 0, 55, MPI_COMM_WORLD, &mpistat);        MPI_Recv(&dataArr[0], num, MPI_INT, 0, 55, MPI_COMM_WORLD, &mpistat);        printf("Received Original Array:\n");for (int i = 0; i< num; i++){            printf("%d ", dataArr[i]);        }        printf("\n");//sort this section        qsort(dataArr, num, sizeof(int), QuickSortCompareFun);

        MPI_Send(&dataArr[0], num, MPI_INT, 0, 55, MPI_COMM_WORLD);///display        printf("My Sorted Section:\n");for (int i = 0; i< num; i++){            printf("%d ", dataArr[i]);        }        printf("\n");    }    MPI_Finalize();return 0;}

希望我的这段并行程序初探对您有帮助:-)

转载于:https://www.cnblogs.com/rosting/archive/2011/11/16/2251892.html

“并行程序VS串行程序”——并行程序优化实录相关推荐

  1. AsyncTask——AsyncTask串行and并行

    一.前言 AsyncTask,相信你不会陌生,也许你很幸运,早已了解了AsyncTask这个家伙挖的坑,也许你已经被坑过了,也许你没坑了,然而还没有发觉. 本次笔者将带大家一起来看下AsyncTask ...

  2. 串行、并行、并发,别再傻傻分不清了!

    开足码力,码动人生,微信搜索[ 程序员大帝 ],关注这个一言不合就开车的的代码界老司机 本文 GitHub上已经收录 https://github.com/BeKingCoding/JavaKing ...

  3. 并发、并行、同步、异步、进程,线程、串行、并行?一文弄懂八大概念

    并发.并行.同步.异步.进程,线程.串行.并行?一文弄懂八大概念 参考博文:并发.并行.串行.同步.异步的区别? java多线程详解(并发,并行,同步) 文章目录 并发.并行.同步.异步.进程,线程. ...

  4. 串行测试 并行测试_什么是并行测试,为什么要采用它?

    串行测试 并行测试 随着技术的进步,随着组织从手动测试转向Selenium测试自动化 ,测试解决方案变得比以往更具可扩展性. 但是,大多数组织仍在努力的领域之一是可并行运行多个测试的可伸缩性. 许多公 ...

  5. 技能梳理37@stm32+按键+光耦+锁存+串行转并行+继电器

    技能梳理37@stm32+按键+光耦+锁存+串行转并行+继电器 1.项目简介 2.实现逻辑 3.应用场景 #主从机有线控制 #开关操作 4.核心代码梳理 //根据按下的按键执行相应的操作 void h ...

  6. java8新特性【Lambda、Stream API、Optional、Date Time API 、并行流与串行流】

    文章目录 Lambda 表达式 Lambda 表达式的基础语法 方法引用 Lambda 表达式需要"函数式接口"的支持 Java8 内置的四大核心函数式接口 Stream API ...

  7. 51单片机之IO口扩展——74HC595芯片串行转并行实验

    我们都知道通信从大的方面有两种:串行和并行.串行的最大优点是占用总线少,但是传输速率低:并行恰恰相反,占用总线多,传输速率高.市面上有很多这样的芯片,有串入并出的(通俗讲就是 一个一个进,最后一块出来 ...

  8. Activiti并行网关和串行网关区别

    转载出处来自分享牛http://blog.csdn.net/qq_30739519) Activiti多实例任务有并行.串行区分. 并行代表同时进行,如把任务分给5个人来处理,这5个人同时会收到任务, ...

  9. 同步、异步 与 串行、并行的区别

    同步.异步: 指的是能否开启新的线程.同步不能开启新的线程,异步可以. 串行.并行: 指的是任务的执行方式.串行是指多个任务时,各个任务按顺序执行,完成一个之后才能进行下一个.并行指的是多个任务可以同 ...

  10. java sync和async区别_GCD中串行、并行与async、sync的区别

    * author:conowen@大钟 * E-mail:conowen@hotmail.com 队列由一个或多个任务组成,当这些任务要开始执行时,系统会分别把他们分配到某个线程上去执行. 串行队列. ...

最新文章

  1. 青桔单车 chameleon 跨平台实践
  2. 多索引表 (5)创建多索引表
  3. Bit-Z收不到邮箱验证码怎么办(如何添加Bit-Z至邮箱白名单?)
  4. java 方块_哈工大java实验 移动小方块
  5. php soap实例讲解
  6. C#与mongoDB初始环境搭建
  7. ORACLE EBS CUX用户的创建(转)
  8. ligerui php mysql_ligerui中3级联动的数据库例子
  9. 如何隐藏地址栏中的真实地址_代理IP如何隐藏真实IP
  10. 风雨秋招路-CV太难了-记得复盘
  11. 要大容量有福了 Surface P4拆解可更换SSD!
  12. 测试 linux CPU 压力
  13. 用Photoshop进行icon的制作或将其它格式图片转成icon
  14. echarts树形图样式_echarts的树形结构图及参数
  15. 前道道指令、后道道指令暨先天八卦指令、后天八卦指令
  16. 一语道破 到底什么是知识产权?
  17. 肖邦 《第一钢琴协奏曲》E小调,OP.11 个人赏析
  18. 抖音申请 TIKTOK 商标被驳回
  19. AssetBundle(一)——AssetBundle介绍
  20. 来自中国各大高校著名导师的精品课程!绝对精典

热门文章

  1. vue rules 两个输入框不能相等_Vue 学习笔记(二十五):webpack 相关
  2. cxf超时设置不起效_晚上不限时,白天1小时!上海限时长停车场来了
  3. Dirichlet energy and the Laplace equation
  4. QT中PRO文件写法
  5. 18复变函数的积分(四)
  6. 3D数学之柏林噪声(Perlin Noise)
  7. 为什么每个邮件收到后都会有一个htm的附件_Python3.x 发送各种形式的告警邮件内容...
  8. 【Python数据分析】数据挖掘建模——分类与预测——决策树
  9. php 序列化匿名函数,在php中序列化匿名函数
  10. css颜色渐变 移动,CSS颜色渐变