时刻记住要做合格的程序员——一次高性能程序设计实验课后的反思
MSRA实习期间,我们科大班的同学又多了一门课:高性能计算。授课的是新教员Teng。第二周结束的时候Teng布置了一道习题:用MPI实现K-means 或者Qsort的并行程序。
其实大家的学习热情并不高。我也不例外,每天组里面都有任务,软件工程课还有活要干,都很忙。于是匆匆忙忙就写了个K-means的算法交了作业:
1 #include<mpi.h> 2 #include<stdio.h> 3 #include<time.h> 4 #include<string.h> 5 #include<float.h> 6 #include<malloc.h> 7 #include<math.h> 8 #include<random> 9 10 #define D 4 11 #define K 4 12 #define N 100 13 14 const int round=100; 15 const float MAXF=9999; 16 17 typedef struct { 18 float dim[D]; 19 }Point; 20 21 typedef struct { 22 float dim[D]; 23 int n; 24 }CenterFactor; 25 26 int main(int argc,char ** argv) 27 { 28 Point *data,center[K]; 29 int processRank,processNum; 30 int i,j,t; 31 int count; 32 int index; 33 float minn,dist; 34 int singleNum,leftNum; 35 MPI_Status mpistat; 36 MPI_Datatype pointType,oldType[1]; 37 int blockCounts[1]; 38 MPI_Aint offsets[1]; 39 CenterFactor *centerFactor,centerTmp; 40 MPI_Request mpireq; 41 42 43 MPI_Datatype centerType,oldTypeCenter[2]; 44 int blockCountsCenter[2]; 45 MPI_Aint offsetsCenter[2],extent; 46 47 48 MPI_Init(&argc,&argv); 49 MPI_Comm_size(MPI_COMM_WORLD,&processNum); 50 MPI_Comm_rank(MPI_COMM_WORLD,&processRank); 51 52 53 offsets[0]=0; 54 oldType[0]=MPI_FLOAT; 55 blockCounts[0]=D; 56 MPI_Type_struct(1,blockCounts,offsets,oldType,&pointType); 57 MPI_Type_commit(&pointType); 58 59 MPI_Address(¢erTmp,&offsetsCenter[0]); 60 MPI_Address(¢erTmp.n,&offsetsCenter[1]); 61 offsetsCenter[1]-=offsetsCenter[0]; 62 offsetsCenter[0]=0; 63 oldTypeCenter[0]=MPI_FLOAT; 64 blockCountsCenter[0]=D; 65 oldTypeCenter[1]=MPI_INT; 66 blockCountsCenter[1]=1; 67 MPI_Type_struct(2,blockCountsCenter,offsetsCenter,oldTypeCenter,¢erType); 68 MPI_Type_commit(¢erType); 69 70 71 72 printf("MPI program: processNum=%d , processRank=%d ",processNum,processRank); 73 fflush(stdout); 74 singleNum=N/(processNum-1); 75 76 if (processRank==0) 77 { 78 srand((unsigned int)time(NULL)); 79 data=(Point *)malloc(sizeof(Point)*(N)); 80 for (i=0;i<N;i++) 81 { 82 for (j=0;j<D;j++) 83 { 84 data[i].dim[j]=rand()/100; 85 } 86 } 87 for (i=0;i<K;i++) 88 { 89 memcpy(center+i,data+i,sizeof(Point)); 90 } 91 92 MPI_Request *mpireqs = (MPI_Request*)malloc(sizeof(MPI_Request) * (processNum - 1)); 93 MPI_Status *mpistats = (MPI_Status*)malloc(sizeof(MPI_Status) * (processNum - 1)); 94 for (i=1;i<processNum;i++) 95 { 96 if (i==processNum) 97 { 98 leftNum=N-singleNum*(processNum-2); 99 }100 else leftNum=singleNum;101 MPI_Isend(data+singleNum*(i-1),leftNum,pointType,i,55,MPI_COMM_WORLD,&mpireqs[i - 1]);102 } 103 ::MPI_Waitall(processNum - 1, mpireqs, mpistats); 104 free(mpistats);105 free(mpireqs);106 centerFactor=(CenterFactor*)malloc(sizeof(CenterFactor)*K*processNum);107 108 }109 else 110 {111 if (processRank==processNum-1)112 {113 leftNum=N-singleNum*(processNum-2);114 }115 else leftNum=singleNum;116 117 data=(Point *)malloc(sizeof(Point)*leftNum);118 MPI_Recv(data,leftNum,pointType,0,55,MPI_COMM_WORLD,&mpistat);119 120 centerFactor=(CenterFactor*)malloc(sizeof(CenterFactor)*K);121 }122 123 count=0;124 while(count++<round)125 {126 if (processRank==0)127 {128 MPI_Request *mpireqs = (MPI_Request*)malloc(sizeof(MPI_Request) * 2 * (processNum - 1));129 MPI_Status *mpistats = (MPI_Status*)malloc(sizeof(MPI_Status) * 2 * (processNum - 1));130 for (i=1;i<processNum;i++)131 {132 MPI_Isend(center,K,pointType,i,55,MPI_COMM_WORLD,&mpireqs[i - 1]);133 }134 135 for (i=1;i<processNum;i++)136 {137 MPI_Irecv(centerFactor+K*i,K,centerType,i,55,MPI_COMM_WORLD,&mpireqs[(processNum - 1) + (i - 1)]);138 }139 140 MPI_Waitall( 2 * (processNum - 1), mpireqs, mpistats ); 141 free(mpistats);142 free(mpireqs);143 144 for (i=0;i<K;i++)145 {146 centerFactor[i].n=0;147 for (j=0;j<D;j++)148 {149 centerFactor[i].dim[j]=0;150 }151 }152 153 for (i=1;i<processNum;i++)154 for (j=0;j<K;j++)155 {156 centerFactor[j].n+=centerFactor[K*i+j].n;157 for (t=0;t<D;t++)158 {159 centerFactor[j].dim[t]+=centerFactor[K*i+j].dim[t];160 }161 }162 163 for (i=0;i<K;i++)164 {165 //if (centerFactor[i])166 for (j=0;j<D;j++)167 {168 if (centerFactor[i].n!=0)169 centerFactor[i].dim[j]/=centerFactor[i].n;170 center[i].dim[j]=centerFactor[i].dim[j];171 }172 }173 }174 else 175 {176 MPI_Recv(center,K,pointType,0,55,MPI_COMM_WORLD,&mpistat);177 for (i=0;i<K;i++)178 {179 centerFactor[i].n=0;180 for (j=0;j<D;j++)181 {182 centerFactor[i].dim[j]=0;183 }184 }185 186 187 for (i=0;i<leftNum;i++)188 {189 minn=FLT_MAX; 190 for (j=0;j<K;j++)191 {192 dist=0;193 for (t=0;t<D;t++)194 {195 dist+=(center[j].dim[t]-data[i].dim[t])*(center[j].dim[t]-196 197 data[i].dim[t]);198 }199 dist=sqrt(dist);200 if (dist<minn)201 {202 index=j;203 minn=dist;204 } 205 }206 centerFactor[index].n++;207 for (j=0;j<D;j++)208 {209 centerFactor[index].dim[j]+=data[i].dim[j];210 }211 }212 MPI_Send(centerFactor,K,centerType,0,55,MPI_COMM_WORLD);213 }214 215 printf("Round %d\n",count);216 for (i=0;i<K;i++)217 {218 printf("Center %d: ",i);219 for (j=0;j<D;j++)220 {221 printf("%lf ",center[i].dim[j]);222 }223 printf("\n");224 } 225 }226 227 free(data);228 free(centerFactor);229 230 MPI_Type_free(&pointType);231 MPI_Type_free(¢erType);232 MPI_Finalize();233 234 }
当时还是回到宾馆,躺在床上敲的。满脑子只想着快点over,然后提交作业。没有注释,没有细分函数,简直就像一陀堆在一起的砖头。甚至连自己都不想再看这个dirty的程序了。
过了两天Teng给我发了feedback邮件。结果让我很惊讶。
没想到Teng会认真地阅读程序的每一行,然后仔细的给出每一点意见。他先表扬了我的几个优点,比如作业提交的最快,用到了自定义结构、非阻塞调用等,然后指出程序的不足,如在程序的那个地方需要加上free()函数释放内存,哪一行应该用MPI_Waitall() 而不是MPI_Wait() ,用MPI_Scatterv()和MPI_Reduce ()来代替逐个进程调用MPI_Send()可以大大提高效率。
一共有13个同学提交了程序,Teng 对每一个同学都认真的回复了.真不知道他在阅读我们的dirty的代码上花了多少时间。有人猜测,Teng给我批改花的时间不会少于我们写程序的时间。在科大呆了三年,从未碰到一个老师/助教会对一件事这么负责。我们老是说自己很忙,现在想想,“忙”只是一种借口,一种不知不觉中被我们当作偷懒的工具罢了。
在被Teng的态度感动的同时,也对自己草率应付的心态感到羞愧。何时才能一名优秀的程序员?或许我要做的第一步,就是时刻记得,写代码,要对得起自己,对得起别人。
转载于:https://www.cnblogs.com/rosting/archive/2011/11/14/2248952.html
时刻记住要做合格的程序员——一次高性能程序设计实验课后的反思相关推荐
- 什么样的程序员才能算是一个合格的程序员呢?
合格的程序员不是根据代码的行数来判断的,代码敲得飞一般的速度,只能说是个不错的打字员. 程序是为解决实际问题而存在的,要解决生活中的实际问题,掌握基本的语言知识是前提,敏捷的思维才是最有效的保障,思想 ...
- 如何成为一个合格的程序员?
想要成为一个合格的程序员,往往需要满足以下几点要求: 一.细心 对于很多程序员来说,写出来的代码可能这里因为不小心漏了什么,那里因为不小心没有测试出一个Bug,这里少个符号,哪里多个空格等等,因为马虎 ...
- 如果你是合格的程序员或者你认为自己是计算机科学家
如果你认为自己应该是计算机科学家,那么,你应该做如下的事情: 1,你学的第一门语言应该是C++,第二门是汇编 2,你应该对数学的掌握不差于数学专业的比较差的学生,对于数论那些东西你也应该会 3,你应该 ...
- 如何招聘一个合格的程序员?
如何招聘一个合格的程序员? 发表于2012-12-03 16:29| 11559次阅读| 来源TheNextWeb| 23 条评论| 作者张祺 招聘程序员 摘要:作者是ApeForest和Conten ...
- 怎样才算得上合格的程序员
转自:http://blog.csdn.net/B9Q8e64lO6mm/article/details/78829370 最近同一部门另一个项目组的一位程序员被"主动离职"了,虽 ...
- 怎样才算得上合格的程序员,教你一招
对于程序员而言,技术过关当然是非常重要的,这是硬实力.然而只会技术也是不行的,毕竟大多数的程序员还是要与人打交道,软实力也是不可或缺的.怎样才能算合格,我认为有以下几点: 扎实的基础 计算机领域是一个 ...
- 怎样成为一个合格的程序员
成为程序员就意味着要开启程序生涯,开始敲代码,如果说做程序员仅仅为了高工资,那么就不必做了.一天天干坐着只为等工资那么奉劝你,另谋高就. 学编程应该在编程中感受到快乐,不然每天对着没有表情的字母,很是 ...
- 一个合格的程序员所具备的素质和修养
程序员基本素质: 作一个真正合格的程序员,或者说就是可以真正合格完成一些代码工作的程序员,应该 具有的素质. 1:团队精神和协作能力 把它作为基本素质,并不是不重要,恰恰相反,这是程序员应该具备的最基 ...
- 《我也能做CTO之程序员职业规划》之十六:逆商
<我也能做CTO之程序员职业规划 >之十六:逆商Adversity Quotient (=AQ) 本文选自<我也能做CTO之程序员职业规划 >一书 锐哥想在工作之余到小蔡学校进 ...
最新文章
- 5号发工资和25号发工资,真能看出公司是否靠谱?
- Python Django 多表设计OneToOneField/ManyToManyField/ForeignKey
- origin画图_把heatmap翻一转:imshow的origin和extent
- java executor_Java并发编程(08):Executor线程池框架
- python标准库os的方法listdir_使用python标准库快速修改文件名字
- Linux——umask使用详解
- 以下不属于时序逻辑电路的有_静态时序分析圣经翻译计划——附录B:SDF
- 如何重启apache2服务
- node.weiChat
- 如何稳定地使用 Google 搜索
- matlab位姿,matlab位姿解算的相关问题,求助求助!
- 怎么让联想计算机升级,如何刷bios,教您联想电脑如何刷bios
- mac M1 下安装docker 及相关镜像
- 计算机桌面的文件拒绝访问,文件或文件夹拒绝访问的解决方法
- 关于android百度导航不能出声音的解决办法
- Markdown数学公式语法、常用符号与字体
- 1034-乘积小于 K 的子数组
- 按摩界的“爱马仕”,拯救你的发际线,失眠、职业病通通消失,爽爆了!
- 2017夸专业计算机考研,2017跨专业考研有难度吗?
- 码元速率、数据速率、信道带宽、信道容量、载波的概念
热门文章
- 详细解析RxAndroid的使用方式
- 《深入理解Nginx》阅读与实践(一):Nginx安装配置与HelloWorld
- Andrew Ng机器学习公开课笔记 -- 朴素贝叶斯算法
- 第14讲 转换与比较指令
- 第8章 静态路由配置
- MOQL—筛选器(Selector)(三)
- Leetcode 687.最长同值路径
- 【前端】CSS使用总结
- springmvc web.xml和application.xml配置详情(附:完整版pom.xml)
- RabbitMQ学习之Publish/Subscribe(3)