并行计算课程设计报告.docx

上传人:b****3 文档编号:5530093 上传时间:2022-12-18 格式:DOCX 页数:49 大小:320.35KB
下载 相关 举报
并行计算课程设计报告.docx_第1页
第1页 / 共49页
并行计算课程设计报告.docx_第2页
第2页 / 共49页
并行计算课程设计报告.docx_第3页
第3页 / 共49页
并行计算课程设计报告.docx_第4页
第4页 / 共49页
并行计算课程设计报告.docx_第5页
第5页 / 共49页
点击查看更多>>
下载资源
资源描述

并行计算课程设计报告.docx

《并行计算课程设计报告.docx》由会员分享,可在线阅读,更多相关《并行计算课程设计报告.docx(49页珍藏版)》请在冰豆网上搜索。

并行计算课程设计报告.docx

并行计算课程设计报告

 

并行计算与多核多线程技术

课程报告

 

专业

班级

学号

 

成绩___________________

 

年月日

 

课程报告要求

手写容:

设计目的、意义,设计分析,方案分析,功能模块实现,最终结果分析,设计体会等。

  允许打印容:

设计原理图等图形、图片,电路图,源程序。

硬件类的设计,要有最终设计的照片图;软件类设计,要有各个功能模块实现的界面图、输入输出界面图等。

评价

理论根底

 

实践效果〔正确度/加速比〕

 

难度

 

工作量

 

独立性

 

 

1.设计目的、意义〔功能描述〕

设计一个计算向量夹角的WinForm窗体应用,用户只需要在窗体上输入向量的维度,系统随机产生两个向量并将计算结果显示在窗体上。

求两个n维向量的夹角,要用到求向量夹角的数学公式,当向量维度较小时计算量不大,而当维度过大时特别是百万级甚至千万级别的时候计算量就很大了,用并行计算求向量夹角,可以将任务分配给多个处理器,减小运算时间。

所以要设计一个并行计算夹角的方法,提高计算速度,把并行和串行计算时间做个比较显示在窗体上。

窗体应用比控制台程序更方便用户操作,简单直观,页面也更加友好。

2.方案分析〔解决方案〕

定义两个数组分别存放两个向量,用for循环将产生的随机数赋值给数组。

假设有两个向量X,YX=〔x1,x2,……,xn〕,Y=〔y1,y2,……,yn〕计算X,Y夹角的公式是:

cos(X,Y)=XY/(|X|·|Y|)=(x1·y1+x2·y2+…+xn·yn)/[(x1²+x2²+…+xn²)1/2·(y1²+y2²+…+yn²)1/2]。

由3个for循环分别实现求向量积和两个向量的模,最后用公式计算即可。

3.设计分析

3.1串行算法设计

输入:

向量的维度n

输出:

两个随机向量的夹角syy_angle

Begin

给存放向量的数组动态分配存空间

Fori=0toi=n-1do

产生随机数给数组x赋值

endFor

Fori=0toi=n-1do

产生随机数给数组y赋值

endFor

Fori=0toi=n-1do

计算向量积

endFor

Fori=0toi=n-1do

计算向量X模

endFor

Fori=0toi=n-1do

计算向量Y模

endFor

利用公式计算夹角

End

3.2并行算法设计

输入:

向量的维度n

输出:

两个随机向量的夹角syy_angle

Begin

给存放向量的数组动态分配存空间

Fori=0toi=n-1do

产生随机数给数组x赋值

endFor

Fori=0toi=n-1do

产生随机数给数组y赋值

endFor

3个for循环串行执行,每个for循环由p个核并行执行:

p个核同时执行第一个for循环

Fori=0toi=n-1do

计算向量积

endFor

p个核同时执行第二个for循环

Fori=0toi=n-1do

计算向量X模

endFor

p个核同时执行第三个for循环

Fori=0toi=n-1do

计算向量Y模

endFor

利用公式计算夹角

End

3.3理论加速比分析

设加速比为S,串行运行时间为Ts,并行的运行时间为Tp。

假设一次运算作为一个时间单位,对于串行算法来说其时间复杂度为O(n)即Ts=O(n),对于并行算法来说,由于有p个处理器同时运行,那么其时间复杂度为O(n/p)即Tp=O(n/p),所以理论加速比S=Ts/Tp=O(n)/O(n/p)=p。

4.功能模块实现与最终结果分析

4.1基于OpenMP的并行算法实现

4.1.1主要功能模块与实现方法

1:

向量x,y赋值,用产生的随机数对存放向量的数组赋值,得到两个随机向量

srand((int)time(0));

//数组X赋值

for(i=0;i

{

j=(int)(100*rand()/(RAND_MAX+1.0));//随机产生的数

x[i]=j;

}

//数组Y赋值

for(i=0;i

{

j=(int)(100*rand()/(RAND_MAX+1.0));//随机产生的数

y[i]=j;

}

2:

计算向量积,向量x,y的模用并行实现。

设置两个线程,用reduction实现并行计算,两个线程都会创立一个reduction变量的私有副本,在OPENMP区域完毕后,将各个线程的计算结果相加赋值给原来的变量。

#pragmaompparallelforreduction(+:

syy_outer_product)

for(i=0;i

{

syy_outer_product=syy_outer_product+x[i]*y[i];//计算向量积

}

计算向量X,Y的模方法与上面类似

4.1.2实验加速比分析

线程数设置为2时,向量维数小时,由于精度问题,运行时间显示为0,加速比无法计算。

向量维数到达百万级以上,加速比介于1到2之间,根据向量维数的变化,加速比有一定的变化但不会超过围。

4.2基于MPI的并行算法实现

4.2.1主要功能模块与实现方法

使用MPI群集通信,由0进程接收输入的数组长度n,给数组动态分配存后,用产生的随机数给数组赋值。

用MPI_Bcast先将数组长度播送给其他进程,由其他进程给数组动态分配存后,再将数组值播送给其他进程。

求向量积,向量模的for由多个进程同时执行,将0到n-1次循环分配给P个进程,每个进程从i=myid开场执行,循环一次i加进程数。

将每个进程的计算结果用MPI_Reduce函数规约。

1:

由0进程进展随机数组动态分配存和赋值操作

if(myid==0)

{

………

//为数组x,y动态分配空间

x=(int*)malloc(n*sizeof(int));

y=(int*)malloc(n*sizeof(int));

srand((int)time(0));

//数组X赋值

for(i=0;i

{

j=(int)(10*rand()/(RAND_MAX+1.0));//随即产生的数

x[i]=j;

}

数组y赋值同上

}

starttime=MPI_Wtime();

}

2:

用MPI_Bcast〔〕函数将数组长度和值播送给其他进程

MPI_Bcast(&n,1,MPI_LONG,0,MPI_COMM_WORLD);//将n值播送出去

MPI_Bcast(x,n,MPI_INT,0,MPI_COMM_WORLD);//将x值播送出去

MPI_Bcast(y,n,MPI_INT,0,MPI_COMM_WORLD);//将y值播送出去

3:

用MPI_Reduce〔〕函数对各个进程的计算结果规约

MPI_Reduce(&my_product,&syy_outer_product,1,MPI_LONG_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD);

MPI_Reduce(&my_mol_x,&syy_mol_x,1,MPI_LONG_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD);

MPI_Reduce(&my_mol_y,&syy_mol_y,1,MPI_LONG_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD);

4:

多个进程同时执行for循环

for(i=syy_myid;i

{

product+=x[i]*y[i];//计算向量积

}

计算向量x,y模与上面类似

5:

串行局部由0进程完成,在执行完并行计算后,再由0进程单独完成串行操作.if(syy_myid==0)里执行的串行操作

4.2.2实验加速比分析

并行时间比串行时间要长,加速比低于1,MPI并行是进程间相互通信传递数据。

设置两个进程时,在0进程里输入向量维度,由0进程对向量数组赋值。

再将n值和x,y动态数组播送给其他进程。

串行计算只有0进程独立完成,可能是进程间通信过多使并行额外开销太大。

4.3基于Java的并行算法实现

4.3.1主要功能模块与实现方法

1:

继承Thread类,创立两个线程thread1,thread2。

用start方法开场线程。

使用join〔〕方法等待线程完毕后再继续执行。

javaandthread1=newjavaand(0,n,x,y);

javaandthread2=newjavaand(1,n,x,y);

startTime=System.currentTimeMillis();

thread1.start();

thread2.start();

thread1.join();

thread2.join();

2:

两个线程同时执行run函数,thread1循环从0到n-1,每次循环i加2,thread2循环从1到n-1,每次循环i加2.最后两个线程的计算结果相加

publicvoidrun(){

for(longi=start;i

syy_outer_product+=x[(int)i]*y[(int)i];//计算向量积

}

for(longi=start;i

syy_mol_x+=x[(int)i]*x[(int)i];//计算向量X模

}

for(longi=start;i

syy_mol_y+=y[(int)i]*y[(int)i];//计算向量Y模

}

}

3:

用count函数实现串行计算,循环从0到n-1,每次循环i加1.循环局部代码与run方法中类似。

分别用三个循环计算向量积,向量X,Y模后再根据公式计算向量夹角,最后返回运算结果。

4.3.2实验加速比分析

数据量较小时,串并行显示的时间都为0,因此无法计算加速比,当数据量较大时加速比控制在1-2之间。

输入向量的维度超过100000000时,出现存溢出,无法计算加速比。

数组长度定义过大时,程序消耗存过大会出现存溢出,即使是修改JVM-Xmx参数后,向量维度也不能超过100000000

4.4基于WindowsAPI的并行算法实现

4.4.1主要功能模块与实现方法

1:

创立两个线程thread1,thread2,分别指定线程函数为ThreadOneThreadTwo创立成功后返回线程的句柄,等待两个线程计算完后将两个线程的执行结果相加

HANDLEthread1=CreateThread(NULL,0,ThreadOne,NULL,0,NULL);

HANDLEthread2=CreateThread(NULL,0,ThreadTwo,NULL,0,NULL);

WaitForMultipleObjects(2,finish,true,INFINITE);

for(inti=0;i<2;i++)

{

syy_outer_product+=product[i];

syy_mol_x+=mol_x[i];

syy_mol_y+=mol_y[i];

}

2:

并行线程函数,将n次循环分成两局部,线程函数ThreadOne执行前半局部操作,函数ThreadTwo执行后半局部操作

Thread1线程函数负责for循环从0到〔n/2〕-1:

DWORDWINAPIThreadOne(LPVOIDparam)

Thread2线程函数负责for循环从n/2到n-1:

DWORDWINAPIThreadTwo(LPVOIDparam)

3:

线程函数ThreadThree作为单线程执行,for循环从0到n-1

DWORDWINAPIThreadThree(LPVOIDparam)

4.4.2实验加速比分析

串行和并行运算结果一样,但并行比串行时间大。

从理论上分析,两个线程同时执行for循环,加速比应该在1-2之间,而实际情况是并行比串行时间还久。

WaitForMultipleObjects(2,finish,true,INFINITE);这句运行时间长,使用WaitForMultipleObjects

函数是让线程进入等待状态,直到finishi指向的核对象都变为已通知状态。

先完成工作的处理器要等待未完成工作的处理器,处理器空闲时间太大可能会造成并行比串行时间大。

4.5基于.net的并行算法实现

4.5.1主要功能模块与实现方法

1:

创立ThreadStart代理,即thread1,thread2。

指定Work类的sum函数作为两个线程执行的线程函数。

将thread1,thread2代理传递给Thread类的构造函数,最后调用Thread类的Start方法开启线程。

Join方法可以保证应用程序域等待异步线程完毕后才终止运行。

Workwork1=newWork(0,n,x,y);

ThreadStartthread1=newThreadStart(work1.Sum);

Threadnewthread1=newThread(thread1);

Workwork2=newWork(1,n,x,y);

ThreadStartthread2=newThreadStart(work2.Sum);

Threadnewthread2=newThread(thread2);

2:

用于实现并行计算的Work类的Sum函数。

newthread1执行的循环是从0到n-1,每次循环i加2。

newthread2执行的循环是从1到n-1,每次循环i加2。

计算向量积的for循环如下:

for(longi=start;i

{

syy_outer_product+=x[i]*y[i];//计算向量积

}

3:

调用Work类的sumto函数实现串行计算,并返回计算得到的夹角。

用3个for循环分别计算向量积和x,y的模,循环从0到n-1,每次i加1,最后用公式计算夹角。

4.5.2实验加速比分析

设置两个线程同时计算,能得到较理想的加速比,数据量为十几时,加速比在1.8左右,数据量到达10000000000时,加速比能接近1.9.从总体的运行结果看,加速比在1.7到1.9之间,符合理论加速比的分析。

4.6并行计算技术在实际系统中的应用

4.6.1主要功能模块与实现方法

1:

确认按钮点击事件函数,当点击确认按钮后从文本框中获取向量的维度,传递给count函数:

privatevoidconfirm_Click(objectsender,EventArgse)

2:

从窗体中获取向量维度后用count函数计算夹角,并把结果返回给窗体。

用并行和串行方法计算的代码全部放在count函数里进展

publicvoidcount(longn)

3:

创立两个线程实现并行计算

创立两个线程代理thread1,thread2指定线程函数Work类里的Sum函数,然后将ThreadStart代理传递给Thread类的构造函数

Workwork1=newWork(0,n,x,y);

ThreadStartthread1=newThreadStart(work1.Sum);

Threadnewthread1=newThread(thread1);

Workwork2=newWork(1,n,x,y);

ThreadStartthread2=newThreadStart(work2.Sum);

Threadnewthread2=newThread(thread2);

4:

用于实现并行计算的Work类的Sum函数。

newthread1执行的循环是从0到n-1,每次循环i加2。

newthread2执行的循环是从1到n-1,每次循环i加2。

计算向量积的for循环如下:

for(longi=start;i

{

syy_outer_product+=x[i]*y[i];//计算向量积

}

5:

调用Work类的sumto函数实现串行计算,并返回计算得到的夹角。

用3个for循环分别计算向量积和x,y的模,循环从0到n-1,每次i加1,最后用公式计算夹角。

4.6.2实验加速比分析

当数据量较小时加速比接近于1,比较小。

当数据量大的时候,加速比有时会超过2,甚至接近于3,与理论分析的加速比有出入。

可能跟WinForm窗体运行环境有关,用C#语言写的程序占用存小加速比高。

5.设计体会

这次课程设计是用了5种不同的方法实现求n维随机向量的夹角,在具体的编程过程中遇到了很多问题,在解决问题过程中也有不少收获,下面我就这五种实现方法谈谈我的设计体会。

用OpenMP编程时为了解决数据竞争的问题,我使用了reduction字句,在进入并行区域后两个线程就有各自的变量的副本,只要变量不公用,就不存在数据竞争的问题。

OpenMP的编程是在parallel并行区并行计算,我觉得相比其他四个编程方法这个更简单。

在MPI编程中,我遇到了最大的问题是不知道如何播送动态数组,后来上网查询,找到了一个解决方案是先将数组长度播送出去,然后非0进程动态非配空间后再播送该数组。

用java语言编写程序时,很多程序语言需要利用外部的线程软件包来实现多线程,而java语言那么在支持多线程,它的所有类都是在多线程的思想下定义的。

Java编程中实现多线程有两种方法:

一种是用户在自己定义的类中使用Runnable接口,另一种是继承Thread类。

我用的就是第二种方法,在run函数中实现并行,在count函数中实现串行。

.net编程有很多地方与java相似,用两个线程做并行计算,都要先创立进程,但.net创立线程首先需要创立ThreadStart代理,指定线程执行的线程函数,然后再创立Thread类线程,将ThreadStart代理传递给Thread类的构造函数。

线程函数有点类似于javaThread类里的run函数,都是两个线程同时执行的函数。

Win32API编程不需要配置编程环境,应用程序只需要调用相关的函数就行,Win32API提供了一系列处理线程的函数接口,向应用程序提供多线程的功能。

总之,每种实现方法都各有特点。

用不同的语言实现同一种算法,在具体的编程过程中也会有细小的差异,每一次修正错误都是一次学习。

6.附录

6.1基于OpenMP的并行程序设计

6.1.1代码及注释

〔变量名名字首字母开头〕

#include"stdafx.h"

#include

#include

#include

#include

#include

#include

#defineNUM_THREADS2

int_tmain(intargc,_TCHAR*argv[])

{

intj;//随机数

longlongi;

longlongn;

longdoublesyy_outer_product=0,syy_mol_x=0,syy_mol_y=0,syy_angle;//向量积

clock_tt1,t2,t3,t4;

printf("两条n维随即向量的夹角串并行计算\n");

printf("请输入向量的维度:

\n");

scanf("%lld",&n);

//为数组x,y动态分配空间

int*x=(int*)malloc(n*sizeof(int));

int*y=(int*)malloc(n*sizeof(int));

srand((int)time(0));

//数组X赋值

for(i=0;i

{

j=(int)(100*rand()/(RAND_MAX+1.0));//随即产生到的数

x[i]=j;

}

//数组Y赋值

for(i=0;i

{

j=(int)(100*rand()/(RAND_MAX+1.0));//随即产生到的数

y[i]=j;

}

/*串行区域*/

t1=clock();

for(i=0;i

{

syy_outer_product=syy_outer_product+x[i]*y[i];//计算向量积

}

for(i=0;i

{

syy_mol_x=syy_mol_x+x[i]*x[i];//计算向量X模

}

for(i=0;i

{

syy_mol_y=syy_mol_y+y[i]*y[i];//计算向量Y模

}

t2=clock();

t3=t2-t1;//串行时间

syy_mol_x=sqrt(syy_mol_x);

syy_mol_y=sqrt(syy_mol_y);

syy_angle=syy_outer_product/(syy_mol_x*syy_mol_y);

printf("随即产生两个向量,向量的夹角cos(x,y)=%f\n",syy_angle);

printf("串行时间=%d\n",(t2-t1));

syy_mol_x=0;

syy_mol_y=0;

syy_outer_product=0;

omp_set_num_threads(NUM_THREADS);//设置线程数

t1=clock();

/*并行区域*/

#pragmaompparallelforreduction(+:

syy_outer_product)

for(i=0;i

{

syy_outer_product=syy_outer_product+x[i]*y[i];//计算向量积

}

#pragmaompparallelforreduction(+:

syy_mol_x)

for(i=0;i

{

syy_mol_x=syy_mol_x+x[i]*x[i];//计算向量X模

}

#pragmaompparallelforreduction(+:

syy_mol_y)

for(i=0;i

{

syy_mol_y=syy_mol_y+y[i]*y[i];//计算向量Y模

}

t2=clock();

t4=t2-t1;//并行时间

syy_mol_x=sqrt(syy_mol_x);

syy_mol_y=sqrt(syy_mol_y);

syy_angle=syy_outer_product/(syy_mol_x*syy_mol_y);

printf("随即产生两个向量,向量的夹角cos(x,y)=%f\n",syy_angle);

printf("并行时间=%d\n",(t2-t1));

printf("加

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 自我管理与提升

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1