并行计算与多核多线程技术
课程报告
专业 软件工程
班级 计133-2
学号 XXXXXXXXX
姓名 XX
成绩 ____________________
2015年 11月 19日
课程报告要求
手写内容:设计目的、意义,设计分析,方案分析,功能模块实现,最终结果分析,设计体会等。
允许打印内容:设计原理图等图形、图片,电路图,源程序。硬件类的设计,要有最终设计的照片图;软件类设计,要有各个功能模块实现的界面图、输入输出界面图等。
评 价
理论基础
实践效果(正确度/加速比)
难度
工作量
独立性
目 录
1. 设计目的、意义(功能描述)
蒙特·卡罗方法(Monte Carlo method),也称统计模拟方法,是二十世纪四十年代中期由于科学技术的发展和电子计算机的发明,而被提出的一种以概率统计理论为指导的一类非常重要的数值计算方法。本次大作业主要是对蒙特·卡罗方法进行并行处理,通过OpenMP、MPI、.NET、Java、Win32API等一系列并行技术和并行机制对该算法进行并行处理,从而也进一步熟悉了蒙特·卡罗方法的串行算法和并行算法,实现了用蒙特·卡罗方法计算出半径为1单位的球体的体积,体会到了并行技术在实际生活中的应用。
2. 方案分析(解决方案)
蒙特·卡罗方法(Monte Carlo method)是指使用随机数(或更常见的伪随机数)来解决很多计算问题的方法。球的体积可以估算为:位于点模型内随机点个数与全体随机点个数的比值乘以包围盒的体积算的。
3. 设计分析
3.1 串行算法设计
假定球体用B表示,半径r=1单位,B1是包含B的参考立方体(在本例中是边长为2的正方体),在B1中产生N个均匀分布的伪随机点。对每个随机点检测其是否在B内,假设位于B内的随机点个数为N(in)(<=N),应用蒙特卡洛算法,则B的体积为
V=V1(N(in)/N)
其中V1是B1的体积。如果产生足够多的随机点,理论上可以获得任意逼近精度。
算法描述如下:
BEGIN
N=_MAX;
FOR I=0;I<_MAX;I++
X=RANDOM();
Y=RANDOM();
Z=RANDOM();
IF (X*X+Y*Y+Z*Z)<=1
COUNT++;
END IF;
END FOR;
BULK=V1*(COUNT/_MAX);
END;
本算法主要是在参考立方体的选取上和定义的_MAX的值对结果影响较大,所以应该选择合适的数。
3.2 并行算法设计
对FOR循环进行划分使用两个处理器完成计算。例如对一个长为n的序列,首先划分得到两个长为n/2的序列,将其交给两个处理器分别处理;而后进一步划分得到四个长为n/4的序列,再分别交给四个处理器处理;如此递归下去最终得到结果。当然这是理想的划分情况,如果划分步骤不能达到平均分配的目的,那么结果的效率会相对较差。
伪代码如下:
BEGIN
N=_MAX;
FOR1 I=0;I<_MAX/2;I++
X1=RANDOM();
Y1=RANDOM();
Z1=RANDOM();
IF (X1*X1+Y1*Y1+Z1*Z1)<=1
COUNT1++;
END IF;
END FOR1;
FOR2 I=_MAX/2+1;I<_MAX;I++
X2=RANDOM();
Y2=RANDOM();
Z2=RANDOM();
IF (X2*X2+Y2*Y2+Z2*Z2)<=1
COUNT2++;
END IF;
END FOR2;
BULK=V1*((COUNT1+ COUNT2)/_MAX);
END;
3.3 理论加速比分析
实验中大量数据所产生的加速比比小量数据所产生的加速比要体现得更明显,并且数据生成的并行加速比随着处理器核的增加而增加。设处理器个数为p,数据量为n,由于正常情况下该快速排序算法的复杂度为O(nlogn),并行处理的时间复杂度为O(klogk),其中k=n/p,所以并行算法的时间复杂度为O((n/p)log(n/p)),理论加速比为nlogn/((n/p)log(n/p))=p+logp.
4. 功能模块实现与最终结果分析
4.1 基于OpenMP的并行算法实现
4.1.1 主要功能模块与实现方法
利用了OpenMP里面的#omp parallel sections将对两个for循环用两个线程并行化执行,以多线程方式并行运行程序,并行的算法步骤如下:
(1)初始化_max = 10000000;
(2)创建两个线程;
(3)由OpenMP编译指导语句控制产生并行执行代码区段;
(4)将数据存放到tianqing_count;
(5)各线程调用算法得出结果;
并行算法的部分代码如下:
#pragma omp parallel for private(tianqing_x,tianqing_y,tianqing_z) reduction(+:tianqing_count2)
for (tianqing_i = 0; tianqing_i<tianqing_max; tianqing_i++)
{
tianqing_x = rand();
tianqing_x = tianqing_x / 32767;
tianqing_y = rand();
tianqing_y = tianqing_y / 32767;
tianqing_z = rand();
tianqing_z = tianqing_z / 32767;
if ((tianqing_x*tianqing_x + tianqing_y*tianqing_y + tianqing_z*tianqing_z) <= 1)
tianqing_count2++;
}
tianqing_bulk = 8 * ((double)(tianqing_count2) / tianqing_max);
4.1.2 实验加速比分析
实验中创建了两个线程,通过多次测试,得出实验结果:由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在1.9左右,比较符合常理。
4.2 基于MPI的并行算法实现
4.2.1 主要功能模块与实现方法
主要利用了MPI的MPI_Bcast()函数和MPI_Recv()函数进行各个进程之间的通信,算法步骤如下:
(1)初始化_max = 10000000;
(2)动态申请2个数组,分别记录分块的起始地址、各个进程所获得的数据个数;
(3)各个进程之间进行通信,发送接收各个进程的起始地址与数据大小;
(4)并行执行算法;
(5)得出结果;
伪代码如下:
//初始化MPI执行环境
MPI_Init(&argc, &argv);
//用MPI_Comm_rank 获得进程的rank,该rank值为到p-1间的整数,相当于进程的ID
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
//用MPI_Comm_size 获得进程个数 int MPI_Comm_size(MPI_Comm comm, int *size);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Get_processor_name(processor_name, &namelen);
MPI_Bcast(&tianqing_n,1,MPI_INT,0,MPI_COMM_WORLD);//将tianqing_n值广播出去
算法执行;
MPI_Reduce(&tianqing_bulk, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);//各个进程并行计数得到的计数总和
获得结果。
4.2.2 实验加速比分析
实验中使用了两个处理器,因此理论加速比应该为2,通过多次测试,得出实验结果:加速比:1.976906139262282,由于客观因素的影响,结果合理。
4.3 基于Java的并行算法实现
4.3.1 主要功能模块与实现方法
在Java中,创建用户自己的线程类,使用启动线程的start()方法启动线程对象,使之从新建状态转入就绪状态,定义线程操作的run()方法,并定义新的run()方法覆盖原来的run()方法。
伪代码如下:
And thread1=new And(1,10000000);
And thread2=new And(2,10000000);
long startTime=System.currentTimeMillis();
启动线程1和线程2;
等待进程结束;
And and=new And(a,10000000);
bulk1=8*((b*1.0)/tianqing_n);
4.3.2 实验加速比分析
实验中创建了两个线程,通过多次测试,得出实验结果:由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在1.9左右,比较符合常理。
4.4 基于Windows API的并行算法实现
4.4.1 主要功能模块与实现方法
这里主要用到了Win32 API的进入点函数,在进程中创建一个线程时,也必须给这个线程提供一个进入点函数。线程函数必须返回一个值,它将成为该线程的退出代码。使用CreateThread()函数创建线程,用WaitForMultipleObject()函数管理线程来监测多个对象。采用SetEvent来设置事件处理线程间的同步问题。
伪代码如下:
DWORD WINAPI ThreadOne(LPVOID param)
{
对前一半数据进行处理;
SetEvent(finish[0]);
return 0;
}
DWORD WINAPI ThreadTwo(LPVOID param)
{
对后一半数据进行处理;
SetEvent(finish[1]);
return 0;
}
创建两个事件;
HANDLE thread1=CreateThread(NULL,0,ThreadOne,NULL,0,NULL);//两个并行线程
HANDLE thread2=CreateThread(NULL,0,ThreadTwo,NULL,0,NULL);
WaitForMultipleObjects(2,finish,true,INFINITE);
得出结果;
4.4.2 实验加速比分析
实验中创建了两个线程,通过多次测试,得出实验结果:由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在1.6左右。
4.5 基于.net的并行算法实现
4.5.1 主要功能模块与实现方法
先创建ThreadStart代理,指定要由该线程执行的线程函数,然后将ThreadStart代理传递给Thread类的构造函数,调用Thread类的Start方法启动新的线程然后调用Join()方法保证应用程序域等待异步程序结束后才终止运行。
伪代码如下:
Stopwatch stopwatch = new Stopwatch();
创建Work类的对象work1;
ThreadStart thread1 = new ThreadStart(() => work1.pSumto(b, 0, MAXN - 1));
Thread newthread1 = new Thread(thread1);
创建Work类的对象work2;
ThreadStart thread2 = new ThreadStart(() => work2.pSumto(c, 0, MAXN - 1));
Thread newthread2 = new Thread(thread2);
stopwatch.Start();
启动线程1和线程2;
等待进程结束;
stopwatch.Stop();
得到结果;
4.5.2 实验加速比分析
实验中创建了两个线程,通过多次测试,得出实验结果:由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在2.6~2.7左右。
4.6 并行计算技术在实际系统中的应用
4.6.1 主要功能模块与实现方法
该飞机订票系统主要实现了对机票的一些基本信息进行存储和管理的功能。在系统中实现了对机票信息的增删改查,考虑到查询的方便性,对机票按照航班号进行排序,而此排序方法用并行快速排序运用进来。利用OpenMP的并行技术,对机票信息按顺序排列好,并分析了实验过程中的加速比。
4.6.2 实验加速比分析
实验中创建了两个线程,通过多次测试,得出实验结果:当数据量比较大时,加速比理论在1.9左右。数据量较大时体现出来的加速比更准确。由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在2.2~2.4左右。
5. 设计体会
虽然没有按时完成作业,但这份报告花了我好几天的时间,从开始的搭建并行计算平台到最后的程序运行成功可以说是对我的一个锻炼。每一次的遇到问题与每一次的解决问题都是一个成长。每一次遇到问题和解决问题都是一种锻炼,一种尝试,从我们上并行计算课我懂得了很多电脑硬件和软件的知识,这些可能对于我们这个专业以后都是没有机会接触的,所以我觉得选择了并行计算与多核多线程技术这门课是非常正确的。对OpenMP、MPI、WIN32API、Java、.NET的并行技术有了一定的了解。在搭建MPI并行程序这块,学习的知识尤为增加,这些都是在不断的摸索、学习中学会的。
这次的大作业虽然是对以前实验的整合,但它加深了我对并行计算的印象,也使我对并行计算知识的理解更加深刻,也使我认识到了自己很多不足之处。学习并行计算的历程不会因为完成本次大作业而停止,我们是为了用知识武装大脑而学习,通过学习充实自己的生活,要努力学习,争取以后能够完成规模更大的程序。
6. 附录
6.1 基于OPENMP的并行程序设计
6.1.1 代码及注释
#include <Windows.h>
#include<iostream>
#include<stdlib.h>
#include<time.h>
using namespace std;
long int tianqing_max = 10000000;
long int tianqing_i, tianqing_count1 = 0,tianqing_count2 = 0;
double tianqing_x, tianqing_y, tianqing_z, tianqing_bulk, tianqing_start_time, tianqing_end_time;
void Mframe();
void C_Bulk()
{
tianqing_start_time = clock();
time_t tianqing_t;
srand((unsigned)time(&tianqing_t));//函数产生一个以当前时间开始的随机种子
for (tianqing_i = 0; tianqing_i<tianqing_max; tianqing_i++)
{
tianqing_x = rand();
//生成0~RAND_MAX之间的一个随机数,其中RAND_MAX 是stdlib.h 中定义的一个整数,它与系统有关。
/*RAND_MAX是VC中stdlib.h中宏定义的一个字符常量:
#define RAND_MAX 0x7FFF 其值最小为32767,最大为2147483647
通常在产生随机小数时可以使用RAND_MAX。*/
tianqing_x = tianqing_x / 32767;
tianqing_y = rand();
tianqing_y = tianqing_y / 32767;
tianqing_z = rand();
tianqing_z = tianqing_z / 32767;
if ((tianqing_x*tianqing_x + tianqing_y*tianqing_y + tianqing_z*tianqing_z) <= 1)
tianqing_count1++;
}
tianqing_bulk = 8 * (double(tianqing_count1) / tianqing_max);
tianqing_end_time = clock();
cout << "球体的体积为" << tianqing_bulk << endl;
cout << "串行运算时间为" << (tianqing_end_time - tianqing_start_time) << endl;
}
//(2)并行执行程序:利用 for 语句和归并语句对程序进行并行化。
void B_Bulk()
{
tianqing_start_time = clock();
time_t tianqing_t;
srand((unsigned)time(&tianqing_t));//函数产生一个以当前时间开始的随机种子
#pragma omp parallel for private(tianqing_x,tianqing_y,tianqing_z) reduction(+:tianqing_count2)
//reduction子句为变量指定一个操作符,每个线程都会创建reduction变量的私有拷贝,在OpenMP区域结束处,将使用各个线程的私有拷贝的值通过制定的操作符进行迭代运算,并赋值给原来的变量。
for (tianqing_i = 0; tianqing_i<tianqing_max; tianqing_i++)
{
tianqing_x = rand();
tianqing_x = tianqing_x / 32767;
tianqing_y = rand();
tianqing_y = tianqing_y / 32767;
tianqing_z = rand();
tianqing_z = tianqing_z / 32767;
if ((tianqing_x*tianqing_x + tianqing_y*tianqing_y + tianqing_z*tianqing_z) <= 1)
tianqing_count2++;
}
tianqing_bulk = 8 * ((double)(tianqing_count2) / tianqing_max);
tianqing_end_time = clock();
cout << "球体的体积为" << tianqing_bulk << endl;
cout << "并行运算时间为" << (tianqing_end_time - tianqing_start_time) << endl;
}
int main()
{
B_Bulk();
C_Bulk();
return 0;
}
6.1.2 执行结果截图
加速比为:1609/922= 1.745119305856833。
6.1.3 遇到的问题及解决方案
在运行openMP的并行程序,计算的球体的体积是串行计算的结果的2倍。
分析:
由于在定义tianqing_count变量后,串行和并行用的都是同一个变量,执行完串行程序后tianqing_count变量没有清零,导致了并行的结果是串行的2倍。
解决方法:
分别定义了变量tianqing_count1和tianqing_count2。
6.2 基于MPI的并行程序设计
6.1.1 代码及注释
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <iostream>
#pragma comment (lib, "mpi.lib")
int main(int argc, char* argv[])
{
long int tianqing_n=100000000 ;
long int tianqing_i, tianqing_count = 0,tianqing_done=0;
double tianqing_x, tianqing_y, tianqing_z, tianqing_bulk, tianqing_start_time, tianqing_end_time;
int myid, numprocs;
int namelen;
double mypi,pi;
char processor_name[MPI_MAX_PROCESSOR_NAME];
//初始化MPI执行环境
MPI_Init(&argc, &argv);
//用MPI_Comm_rank 获得进程的rank,该rank值为到p-1间的整数,相当于进程的ID
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
//用MPI_Comm_size 获得进程个数 int MPI_Comm_size(MPI_Comm comm, int *size);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Get_processor_name(processor_name, &namelen);
printf("Process %d of %d on %s\n", myid, numprocs, processor_name);
fflush(stdout);
tianqing_start_time = MPI_Wtime();
MPI_Bcast(&tianqing_n,1,MPI_INT,0,MPI_COMM_WORLD);//将tianqing_n值广播出去
for (tianqing_i = myid+1; tianqing_i < tianqing_n; tianqing_i+=numprocs)
{
tianqing_x = rand();
//生成~RAND_MAX之间的一个随机数,其中RAND_MAX 是stdlib.h 中定义的一个整数,它与系统有关。
/*RAND_MAX是VC中stdlib.h中宏定义的一个字符常量:
#define RAND_MAX 0x7FFF 其值最小为,最大为
通常在产生随机小数时可以使用RAND_MAX。*/
tianqing_x = tianqing_x / 32767;
tianqing_y = rand();
tianqing_y = tianqing_y / 32767;
tianqing_z = rand();
tianqing_z = tianqing_z / 32767;
if ((tianqing_x*tianqing_x + tianqing_y*tianqing_y + tianqing_z*tianqing_z) <= 1)
tianqing_count++;
}
//mypi=tianqing_count;
tianqing_bulk = 8 * (double(tianqing_count) / tianqing_n);
//mypi=tianqing_bulk;
MPI_Reduce(&tianqing_bulk, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);//各个进程并行计数得到的计数总和
if(myid==0)
{
tianqing_end_time = MPI_Wtime();
printf("球体的体积=%f\n", pi);
printf("运算时间=%f\n", tianqing_end_time - tianqing_start_time);
}
MPI_Finalize();
return 0;
}
6.2.2 执行结果截图
串行执行结果:
并行执行结果:
加速比:1.976906139262282
6.2.3 遇到的问题及解决方案
在运行MPI程序后,没有输出结果。
分析:
对MPI的一些函数不理解。
解决方法:
通过看书和询问别人,程序运行成功。
6.3 基于Java的并行程序设计
6.3.1 代码及注释
import java.util.Random;
public class java1 extends Thread{
private long tianqing_start,tianqing_end;
public static long tianqing_n=10000000;
long tianqing_count1 = 0;
public java1(long tianqing_start,long tianqing_end){//构造函数
super();
this.tianqing_start=tianqing_start;
this.tianqing_end=tianqing_end;
}
public void run(){
double tianqing_x, tianqing_y, tianqing_z;
Random random = new Random();
for ( long tianqing_i = tianqing_start; tianqing_i < tianqing_end; tianqing_i+=2)
{
tianqing_x = random.nextDouble();
tianqing_y = random.nextDouble();
tianqing_z = random.nextDouble();
if ((tianqing_x*tianqing_x + tianqing_y*tianqing_y + tianqing_z*tianqing_z) <= 1)
tianqing_count1++;
}
}
public long serial(){ //串行执行函数
double tianqing_x, tianqing_y, tianqing_z;
long tianqing_count2 = 0;
Random random = new Random();
for ( long tianqing_i = tianqing_start; tianqing_i < tianqing_end; tianqing_i++)
{
tianqing_x = random.nextDouble();
tianqing_y = random.nextDouble();
tianqing_z = random.nextDouble();
if ((tianqing_x*tianqing_x + tianqing_y*tianqing_y + tianqing_z*tianqing_z) <= 1)
tianqing_count2++;
}
return tianqing_count2;
}
public long getsum(){
return tianqing_count1;
}
public static void main(String[] args)throws InterruptedException{
double bulk1,bulk2;
long b,c;
java1 thread1=new java1(1,10000000); //创建线程
java1 thread2=new java1(2,10000000);
long startTime=System.currentTimeMillis();
thread1.start(); //直接调用start方法进入执行状态
thread2.start();
System.out.println("并行结果:");
thread1.join(); //避免执行结果出错异常错误
thread2.join();
b=thread1.getsum()+thread2.getsum();
bulk1=8*((b*1.0)/tianqing_n);
System.out.println("\n球的体积为:"+(bulk1));
long endTime=System.currentTimeMillis();
System.out.println("并行时间="+(endTime-startTime));
//串行执行
startTime=System.currentTimeMillis(); //调用系统的currentTimeMillis()进行计时
System.out.println("串行结果:");
java1 serial=new java1(1,10000000);
c=serial.serial();
bulk2 = 8 * ((c*1.0) / tianqing_n);
System.out.println("\n球的体积为:"+(bulk2));
endTime=System.currentTimeMillis();
System.out.println("串行 时间:"+(endTime-startTime));
}
}
6.3.2 执行结果截图
加速比:1.966492926284438
6.3.3 遇到的问题及解决方案
如图所示:求得体积都为零。
分析:
对JAVA中产生随机数的函数不是很了解,不清楚函数产生的随机数在何种范围之内。
解决方法:
通过网上查询和询问别人,程序运行成功。
6.4 基于Windows API的并行程序设计
6.4.1 代码及注释
#include "time.h"
#include <omp.h>
#include <Windows.h>
HANDLE finish[2];
static long tianqing_n = 10000000;
double tianqing_sum[2] = {0.0,0.0};
double tianqing_bulk1, tianqing_bulk2, tianqing_start_time, tianqing_end_time;
DWORD WINAPI ThreadOne(LPVOID param){ // 线程函数
double tianqing_x, tianqing_y, tianqing_z, tianqing_count1 = 0;
for ( int tianqing_i = 0; tianqing_i < (tianqing_n/2); tianqing_i++)
{
tianqing_x = rand();
//生成~RAND_MAX之间的一个随机数,其中RAND_MAX 是stdlib.h 中定义的一个整数,它与系统有关。
/*RAND_MAX是VC中stdlib.h中宏定义的一个字符常量:
#define RAND_MAX 0x7FFF 其值最小为,最大为
通常在产生随机小数时可以使用RAND_MAX。*/
tianqing_x = tianqing_x / 32767;
tianqing_y = rand();
tianqing_y = tianqing_y / 32767;
tianqing_z = rand();
tianqing_z = tianqing_z / 32767;
if ((tianqing_x*tianqing_x + tianqing_y*tianqing_y + tianqing_z*tianqing_z) <= 1)
tianqing_count1++;
}
tianqing_sum[0] = tianqing_count1;
SetEvent(finish[0]); //设置事件状态为激发状态
return 0;
}
DWORD WINAPI ThreadTwo(LPVOID param){
double tianqing_x, tianqing_y, tianqing_z, tianqing_count2 = 0;
for (int tianqing_i = (tianqing_n / 2) + 1; tianqing_i < tianqing_n; tianqing_i++)
{
tianqing_x = rand();
//生成~RAND_MAX之间的一个随机数,其中RAND_MAX 是stdlib.h 中定义的一个整数,它与系统有关。
/*RAND_MAX是VC中stdlib.h中宏定义的一个字符常量:
#define RAND_MAX 0x7FFF 其值最小为,最大为
通常在产生随机小数时可以使用RAND_MAX。*/
tianqing_x = tianqing_x / 32767;
tianqing_y = rand();
tianqing_y = tianqing_y / 32767;
tianqing_z = rand();
tianqing_z = tianqing_z / 32767;
if ((tianqing_x*tianqing_x + tianqing_y*tianqing_y + tianqing_z*tianqing_z) <= 1)
tianqing_count2++;
}
tianqing_sum[1] = tianqing_count2;
SetEvent(finish[1]);
return 0;
}
int main(int argc, char* argv[])
{
double sumparallel = 0;
//并行执行
clock_t start = clock(); //开始计时
finish[0] = CreateEvent(NULL, false, false, NULL); //创建激发线程1的事件
finish[1] = CreateEvent(NULL, false, false, NULL);
HANDLE thread1 = CreateThread(NULL, 0, ThreadOne, NULL, 0, NULL);//创建线程,并且创建之后就会被立即执行
//Sleep(20000); //线程等待
HANDLE thread2 = CreateThread(NULL, 0, ThreadTwo, NULL, 0, NULL);
WaitForMultipleObjects(2, finish, true, INFINITE); //用来检测多个对象,并且保证两个线程的工作能全部完成
for (int i = 0; i < 2;i++)
{
sumparallel+=tianqing_sum[i];
}
tianqing_bulk1 = 8 * (sumparallel/ (tianqing_n*1.0));
clock_t end = clock(); //结束计时
//串行执行
double sumserial = 0;
double tianqing_x, tianqing_y, tianqing_z, tianqing_count3 = 0;;
clock_t start2 = clock();
for (int tianqing_i = 0; tianqing_i < tianqing_n; tianqing_i++)
{
tianqing_x = rand();
tianqing_x = tianqing_x / 32767;
tianqing_y = rand();
tianqing_y = tianqing_y / 32767;
tianqing_z = rand();
tianqing_z = tianqing_z / 32767;
if ((tianqing_x*tianqing_x + tianqing_y*tianqing_y + tianqing_z*tianqing_z) <= 1)
tianqing_count3++;
}
sumserial = tianqing_count3;
tianqing_bulk2 = 8 * ((double)(sumserial) / tianqing_n);
clock_t end2 = clock();
printf("\n并行结果:sumparallel=%lf\n", tianqing_bulk1);
printf("并行计时:parallel time=%lld\n", end - start );
printf("串行计数:sumserial=%lf\n", tianqing_bulk2);
printf("串行计时:serial time=%lld\n", end2 - start2);
return 0;
}
6.4.2 执行结果截图
加速比:1.663282571912014
6.4.3 遇到的问题及解决方案
遇到的问题与Java中的问题一样,都是求得球的体积为零。
分析:
由于程序中不同类型的变量太多,导致在变量之间相互赋值时出现了类型之间转换错误,导致了结果等于0。
解决方法:
通过网上查询和求助别人,程序运行成功。
6.5 基于.net的并行程序设计
6.5.1 代码及注释
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace Net1
{
class Threads
{
static void Main(string[] args)
{
long tianqing_n = 10000000;
double tianqing_bulk1, tianqing_bulk2, sumserial, a;
Stopwatch stopwatch = new Stopwatch(); //用来测量运行时间的类
Work work1 = new Work(1);
ThreadStart thread1 = new ThreadStart(work1.pSumto);
Thread newthread1 = new Thread(thread1);
Work work2 = new Work(2);
ThreadStart thread2 = new ThreadStart(work2.pSumto);
Thread newthread2 = new Thread(thread2);
stopwatch.Start(); //开始测量用于并行执行的时间
newthread1.Start(); //进程1调用start方法,处于就绪状态
newthread2.Start();
newthread1.Join(); //防止异步程序非正常终止
newthread2.Join();
stopwatch.Stop();
TimeSpan timespan = stopwatch.Elapsed; //记录一个时间间隔
sumserial = work1.getSum() + work2.getSum();
tianqing_bulk1 = 8 * ((sumserial) / tianqing_n);
double millseconds = timespan.TotalMilliseconds;//将时间间隔用毫秒的形式表现出来
Console.WriteLine("\nparallel sum={0}", tianqing_bulk1);
Console.Write("parallel time=");
Console.WriteLine(millseconds);
stopwatch.Start(); //开始测量用于串行执行的时间
a=new Work(1).sumto();
tianqing_bulk2=8 * ((a) / tianqing_n);
Console.WriteLine("\nserial sum={0}", tianqing_bulk2);
stopwatch.Stop();
TimeSpan timespan2 = stopwatch.Elapsed;
double millseconds2 = timespan2.TotalMilliseconds;
Console.Write("serial time=");
Console.WriteLine(millseconds2);
}
}
class Work
{
public long start;
public long tianqing_n = 10000000;
double tianqing_sum = 0;
public Work(long i)
{
this.start = i;
}
public void pSumto() //并行执行过程
{
double tianqing_x, tianqing_y, tianqing_z;
Random ran = new Random();
for (long tianqing_i = start; tianqing_i < tianqing_n; tianqing_i += 2)
{
tianqing_x = ran.NextDouble();
tianqing_y = ran.NextDouble();
tianqing_z = ran.NextDouble();
if ((tianqing_x * tianqing_x + tianqing_y * tianqing_y + tianqing_z * tianqing_z) <= 1)
tianqing_sum++;
}
}
public double sumto() //串行执行过程
{
double tianqing_x, tianqing_y, tianqing_z;
double tianqing_count2 = 0;
Random ran = new Random();
for (long tianqing_i = start; tianqing_i < tianqing_n; tianqing_i += 1)
{
tianqing_x = ran.NextDouble();
tianqing_y = ran.NextDouble();
tianqing_z = ran.NextDouble();
if ((tianqing_x * tianqing_x + tianqing_y * tianqing_y + tianqing_z * tianqing_z) <= 1)
tianqing_count2++;
}
return tianqing_count2;
}
public double getSum() //
{
return tianqing_sum;
}
}
}
6.5.2 执行结果截图
加速比:2.765020952420973
6.5.3 遇到的问题及解决方案
问题:
算出的体积不对。
分析:
对.NET中随机数的产生范围不了解。
解决方法:
通过网上查询和求助别人,程序运行成功。
网上查询结果如下:
除了Random.Next()方法之外,Random类还提供了Random.NextDouble()方法产生一个范围在0.0-1.0之间的随机的双精度浮点数:
6.6并行计算技术在实际应用系统的应用
6.6.1 代码及注释
//飞机订票系统+快速排序算法
#include "omp.h"
#include<fstream>
#include<stdio.h>//标准输入、输出头文件
#include<string.h>//包含字符串函数处理头文件
#include<string>
#define N 10000//定义最多的航班数
#define M 10000//定义最大的乘客数
#include <time.h>
using namespace std;
void Mframe();//主界面
struct air //定义飞机结构体数组
{
int num;//定义航班号
string start;//航班起始站
string over;//终点站
string time;//航班日期
string starttime;//航班起飞时间
string overtime;//到达时间void xiugai()
double price; //票价
int zhekou; //折扣
int count;//机票数量
}s[N],b[N],c[N];
struct user //客户信息
{
string uname; //姓名
string unumber; //证件号
int ucount1; //订票数量
int dname; //订单编号
int dnum; //航班号
string dstartcity;//航班起始站
string dovercity;//终点站
string dtime;//航班日期
string dstarttime;//航班起飞时间
string dovertime;//到达时间
double dprice; //票价
}u[M];
int i, m = 0, m3 = 0,count_len1, count_len2;//定义全局变量
char ii[10];
void add();//函数声明增加航班信息函数
void print(); //显示航班信息
void dingpiao();//订票业务
void tuipiao();//退票
void save();//保存文件
void output();//输出格式
void paixu();//航班排序
void paixu1();//按航班号从小到大排序
void paixu2();//从大到小
void xiugai(); //修改航班信息
void search();//查找航班信息
void searchNum();//定义查询函数(按航班号查询)
void searchTime1();//定义查询函数(按起飞时间查询)
void searchTime2();//定义查询函数(按到达时间查询)
void searchCity1();//定义查询函数(按起飞城市查询)
void searchCity2();//定义查询函数(按终点站查询)
void read2(); //读取message.txt
void mymessage(); //我的信息
void quickSort(air A[] , int first , int end );
clock_t time1;
clock_t time2;
void jisubi();
void merge();
#include"aiportF.h"
int main()
{
Mframe();//主界面
return 0;
}
void Mframe() //主界面
{
int a; //序号
cout<<" 欢迎使用华夏飞机订票系统\n"; //打印出系统主界面
cout<<"================================================================================ "<<endl;
cout<<" 1.增加航班信息\n";
cout<<" 2.浏览航班信息\n";
cout<<" 3.查找航班信息\n";
cout<<" 4.航班排序(按航班号)\n";
cout<<" 5.订票业务\n" ;
cout<<" 6.退票业务\n";
cout<<" 7.查看我的信息\n";
cout<<" 8.修改航班信息\n";
cout << " 9.加速比\n";
cout<<" 0.退出\n";
cout<<"================================================================================ "<<endl;
cout<<"请在0-7中选择以回车键结束: ";
cin>>a;
switch(a)
{
case 1:add();//增加数据
break;
case 2:print();//调用显示模块
break;
case 3:search();//调用查找模块
break;
case 4:paixu();//调用排序函数
break;
case 5:dingpiao();//调用订票模块
break;
case 6:tuipiao(); //调用退票模块
break;
case 7:mymessage();//查看我的信息
case 8:xiugai(); //修改航班信息
case 9:jisubi();
case 0://退出系统
save();
cout<<"谢谢使用,再见! ";
break;
default :
cout<<"输入有误!请重新输入!"<<endl;
Mframe();
}
}
void add()//定义增加航班信息函数
{
ofstream outfile1;
outfile1.open("hangban.txt",ios::out);
do{
cout<<"请依次输入航班信息(以回车键结束): "<<endl; //打印提示信息
cout<<"-------------------------------------------------------------------------- "<<endl;
cout<<"请输入航班号: ";
cin>>s[i].num;//输入航班号
cout<<"请输入起始站: ";
cin>>s[i].start;//输入起始站
cout<<"请输入终点站: ";
cin>>s[i].over;//输入终点站
cout<<"请输入时间(星期几): ";
cin>>s[i].time;//输入日期
cout<<"请输入起飞时间:";
cin>>s[i].starttime; //输入起飞时间
cout<<"请输入到达时间:";
cin>>s[i].overtime; //输入到达时间
cout<<"请输入票价:";
cin>>s[i].price; //输入票价
cout<<"请输入票价折扣:";
cin>>s[i].zhekou; //输入票价折扣
cout<<"请输入机票数: ";
cin>>s[i].count;//输入机票数
i++;
m++;
cout<<"添加完毕,是否继续添加?请键入y或n以回车键结束:";
cin>>ii;
}while(!strcmp(ii,"y"));//判断是否继续添加
count_len1 = i / 2;
count_len2 = i - count_len1;
for(int m5=0;m5<i;m5++) //存入”hangban.txt“
{
outfile1<<s[m5].num<<" "<<s[m5].start<<" "<<s[m5].over<<" "<<s[m5].time<<" "<<s[m5].starttime<<" "<<s[m5].overtime<<" "<<s[m5].price<<" "<<s[m5].zhekou<<" "<<s[m5].count<<endl;
}
for (int i1 = 0; i1 < count_len1; i1++)
{
b[i] = s[i];
}
for (int i1 = count_len1; i1 < i; i1++)
{
c[i - count_len1] = s[i];
}
Mframe();
}
void output()//定义输出格式函数
{
cout<<"航班号\t起始\t终点\t日期\t起飞\t到达\t票价\t折扣\t机票数\n";//信息标题
for(i=0;i<m;i++)
{
cout<<s[i].num<<"号\t"<<s[i].start<<"\t"<<s[i].over<<"\t"<<s[i].time<<"\t"<<s[i].starttime<<"\t"<<s[i].overtime<<"\t"<<s[i].price<<"\t"<<s[i].zhekou<<"\t"<<s[i].count<<endl;
}
}
void print()//定义显示航班信息函数
{
cout<<"\n目前我们有如下航班:\n";
output();//调用输出格式函数
cout<<"\n请按回车键返回上层菜单 ";
getchar();
getchar();
Mframe();
}
void search() //查询
{
int x1;
cout<<" 欢迎使用华夏飞机订票系统\n"; //打印出系统主界面
cout<<" -------查询系统\n";
cout<<"================================================================================ "<<endl;
cout<<" 1.按航班号查询\n";
cout<<" 2.按起飞时间查询\n";
cout<<" 3.按到达时间查询\n";
cout<<" 4.按起飞城市查询\n";
cout<<" 5.按终点站查询\n" ;
cout<<" 6.主菜单\n";
cout<<"================================================================================ "<<endl;
cout<<"请在1-6中选择以回车键结束: ";
cin>>x1;
switch(x1)
{
case 1: searchNum();;//按航班号查询
break;
case 2:searchTime1();//按起飞时间查询
break;
case 3:searchTime2();//按到达时间查询
break;
case 4:searchCity1();//按起飞城市查询
break;
case 5:searchCity2();//按终点站查询
break;
case 6:Mframe();//返回主界面
break;
default :
cout<<"输入有误!请重新输入!"<<endl;
search();
}
}
void searchNum()//定义查询函数(按航班号查询)
{
int n;
do
{
cout<<"\n请输入航班号: ";
cin>>n;//输入查询的航班号
for(i=0;i<m;i++)
{
if(s[i].num==n)//按航班号判定输出条件
{
cout<<"\n您所查找的航班信息为:\n ";
cout<<"航班号\t起始\t终点\t日期\t起飞\t到达\t票价\t折扣\t机票数\n";//信息标题
cout<<s[i].num<<"号\t"<<s[i].start<<"\t"<<s[i].over<<"\t"<<s[i].time<<"\t"<<s[i].starttime<<"\t"<<s[i].overtime<<"\t"<<s[i].price<<"\t"<<s[i].zhekou<<"\t"<<s[i].count<<endl;
goto loop;
}
}
cout<<"\n对不起,没有您需要的信息!\n ";
loop:cout<<"是否继续查找?请键入y或n以回车键结束 ";
cin>>ii;
}while(!strcmp(ii,"y"));//判定是否重新查找
search();
}
void searchTime1()//定义查询函数(按起飞时间查询)
{
string time1;
string time2;
do
{
cout<<"\n请输入起飞时间: ";
cin>>time1;//输入起飞时间
for(i=0;i<m;i++)
{
time2=s[i].starttime;
if(time2==time1)//按航班号判定输出条件
{
cout<<"\n您所查找的航班信息为:\n ";
cout<<"航班号\t起始\t终点\t日期\t起飞\t到达\t票价\t折扣\t机票数\n";//信息标题
cout<<s[i].num<<"号\t"<<s[i].start<<"\t"<<s[i].over<<"\t"<<s[i].time<<"\t"<<s[i].starttime<<"\t"<<s[i].overtime<<"\t"<<s[i].price<<"\t"<<s[i].zhekou<<"\t"<<s[i].count<<endl;
goto loop;
}
}
cout<<"\n对不起,没有您需要的信息!\n ";
loop:cout<<"是否继续查找?请键入y或n以回车键结束 ";
cin>>ii;
}while(!strcmp(ii,"y"));//判定是否重新查找
search();
}
void searchTime2()//定义查询函数(按到达时间查询)
{
string time1;
string time2;
do
{
cout<<"\n请输入到达时间: ";
cin>>time1;//输入到达时间
for(i=0;i<m;i++)
{
time2=s[i].starttime;
if(time2==time1)//按航班号判定输出条件
{
cout<<"\n您所查找的航班信息为:\n ";
cout<<"航班号\t起始\t终点\t日期\t起飞\t到达\t票价\t折扣\t机票数\n";//信息标题
cout<<s[i].num<<"号\t"<<s[i].start<<"\t"<<s[i].over<<"\t"<<s[i].time<<"\t"<<s[i].starttime<<"\t"<<s[i].overtime<<"\t"<<s[i].price<<"\t"<<s[i].zhekou<<"\t"<<s[i].count<<endl;
goto loop;
}
}
cout<<"\n对不起,没有您需要的信息!\n ";
loop:cout<<"是否继续查找?请键入y或n以回车键结束 ";
cin>>ii;
}while(!strcmp(ii,"y"));//判定是否重新查找
search();
}
void searchCity1()//定义查询函数(按起飞城市查询)
{
string city1;
string city2;
do
{
cout<<"\n请输入起点站: ";
cin>>city1;//输入起点站:
for(i=0;i<m;i++)
{
city2=s[i].start;
if(city2==city1)//按航班号判定输出条件
{
cout<<"\n您所查找的航班信息为:\n ";
cout<<"航班号\t起始\t终点\t日期\t起飞\t到达\t票价\t折扣\t机票数\n";//信息标题
cout<<s[i].num<<"号\t"<<s[i].start<<"\t"<<s[i].over<<"\t"<<s[i].time<<"\t"<<s[i].starttime<<"\t"<<s[i].overtime<<"\t"<<s[i].price<<"\t"<<s[i].zhekou<<"\t"<<s[i].count<<endl;
goto loop;
}
}
cout<<"\n对不起,没有您需要的信息!\n ";
loop:cout<<"是否继续查找?请键入y或n以回车键结束 ";
cin>>ii;
}while(!strcmp(ii,"y"));//判定是否重新查找
search();
}
void searchCity2()//定义查询函数(按终点站查询)
{
string city1;
string city2;
do
{
cout<<"\n请输入终点站: ";
cin>>city1;//输入终点站:
for(i=0;i<m;i++)
{
city2=s[i].start;
if(city2==city1)//按终点号判定输出条件
{
cout<<"\n您所查找的航班信息为:\n ";
cout<<"航班号\t起始\t终点\t日期\t起飞\t到达\t票价\t折扣\t机票数\n";//信息标题
cout<<s[i].num<<"号\t"<<s[i].start<<"\t"<<s[i].over<<"\t"<<s[i].time<<"\t"<<s[i].starttime<<"\t"<<s[i].overtime<<"\t"<<s[i].price<<"\t"<<s[i].zhekou<<"\t"<<s[i].count<<endl;
goto loop;
}
}
cout<<"\n对不起,没有您需要的信息!\n ";
loop:cout<<"是否继续查找?请键入y或n以回车键结束 ";
cin>>ii;
}while(!strcmp(ii,"y"));//判定是否重新查找
search();
}
void search1() //退订票时用的查询函数
{
int n1;
do
{
cout<<"\n请输入航班号: ";
cin>>n1;//输入查询的航班号
for(i=0;i<m;i++)
{
if(s[i].num==n1)//按航班号判定输出条件
{
cout<<"\n您所查找的航班信息为:\n ";
cout<<"航班号\t起始\t终点\t日期\t起飞\t到达\t票价\t折扣\t机票数\n";//信息标题
cout<<s[i].num<<"号\t"<<s[i].start<<"\t"<<s[i].over<<"\t"<<s[i].time<<"\t"<<s[i].starttime<<"\t"<<s[i].overtime<<"\t"<<s[i].price<<"\t"<<s[i].zhekou<<"\t"<<s[i].count<<endl;
goto loop;
}
}
cout<<"\n对不起,没有您需要的信息!\n ";
loop:cout<<"是否继续查找?请键入y或n以回车键结束 ";
cin>>ii;
}while(!strcmp(ii,"y"));//判定是否继续查找
}
void xiugai()
{
int k1,n1;
k1=m;
if(k1==0)
{
cout<<"请先添加航班信息!"<<endl;
goto loop;
}
do
{
cout<<"\n请输入要修改的航班号: ";
cin>>n1;//输入查询的航班号
for(i=0;i<m;i++)
{
if(s[i].num==n1)//按航班号判定输出条件
{
cout<<"\n您所查找的航班信息为:\n ";
cout<<"航班号\t起始\t终点\t日期\t起飞\t到达\t票价\t折扣\t机票数\n";//信息标题
cout<<s[i].num<<"号\t"<<s[i].start<<"\t"<<s[i].over<<"\t"<<s[i].time<<"\t"<<s[i].starttime<<"\t"<<s[i].overtime<<"\t"<<s[i].price<<"\t"<<s[i].zhekou<<"\t"<<s[i].count<<endl;
cout<<"请重新输入该航班的信息:"<<endl;
cout<<"请输入起始站: ";
cin>>s[i].start;//输入起始站
cout<<"请输入终点站: ";
cin>>s[i].over;//输入终点站
cout<<"请输入时间(星期几): ";
cin>>s[i].time;//输入日期
cout<<"请输入起飞时间:";
cin>>s[i].starttime; //输入起飞时间
cout<<"请输入到达时间:";
cin>>s[i].overtime; //输入到达时间
cout<<"请输入票价:";
cin>>s[i].price; //输入票价
cout<<"请输入票价折扣:";
cin>>s[i].zhekou; //输入票价折扣
cout<<"请输入机票数: ";
cin>>s[i].count;//输入机票数
goto loop1;
}
}
cout<<"\n对不起,没有您需要的信息!\n ";
loop1:cout<<"是否继续修改?请键入y或n以回车键结束 ";
cin>>ii;
}while(!strcmp(ii,"y"));//判定是否继续查找
loop: Mframe();
}
void dingpiao()//定义订票业务函数
{
ofstream outfile2;//存储客户信息
outfile2.open("message.txt",ios::out);
ofstream outfile3;
outfile3.open("hangban.txt",ios::out);
int n;
char a[10]="y";
do
{
int n1,n2;
n2=m;
if(n2==0)
{
cout<<"请先添加航班信息!"<<endl;
goto loop6;
}
do
{
cout<<"\n请输入航班号: ";
cin>>n1;//输入查询的航班号
for(i=0;i<m;i++)
{
if(s[i].num==n1)//按航班号判定输出条件
{
cout<<"\n您所查找的航班信息为:\n ";
cout<<"航班号\t起始\t终点\t日期\t起飞\t到达\t票价\t折扣\t机票数\n";//信息标题
cout<<s[i].num<<"号\t"<<s[i].start<<"\t"<<s[i].over<<"\t"<<s[i].time<<"\t"<<s[i].starttime<<"\t"<<s[i].overtime<<"\t"<<s[i].price<<"\t"<<s[i].zhekou<<"\t"<<s[i].count<<endl;
goto loop;
}
}
cout<<"\n对不起,没有您需要的信息!\n ";
loop:cout<<"是否继续查找?请键入y或n以回车键结束 ";
cin>>ii;
}while(!strcmp(ii,"y"));//判定是否继续查找
cout<<"请输入你的姓名:";
cin>>u[m3].uname;
cout<<"\n请输入你的证件号码(如:372330********6155):";
cin>>u[m3].unumber;
u[m3].dnum=s[i].num;//订单号
cout<<"请输入起飞城市:";
loop1:cin>>u[m3].dstartcity;
if(u[m3].dstartcity!=s[i].start)
{
cout<<"信息输入有误,请重新输入起飞城市:";
goto loop1;
}
cout<<"请输入终点城市:";
loop2:cin>>u[m3].dovercity;
if(u[m3].dovercity!=s[i].over)
{
cout<<"信息输入有误,请重新输入终点城市:";
goto loop2;
}
cout<<"请输入日期(星期几):";
loop3:cin>>u[m3].dtime;
if(u[m3].dtime!=s[i].time)
{
cout<<"信息输入有误,请重新输入日期(星期几):";
goto loop3;
}
cout<<"请输入起飞时间:";
loop4:cin>>u[m3].dstarttime;
if(u[m3].dstarttime!=s[i].starttime)
{
cout<<"信息输入有误,请重新输入起飞时间:";
goto loop4;
}
u[m3].dovertime=s[i].overtime;
u[m3].dprice=s[i].price;
do
{
cout<<"请输入您要订的机票数(以回车键结束): ";
cin>>n;//输入所订机票数
if(n<=0)//判定机票数是否出错
{
cout<<"输入错误!至少需订1张机票。\n";
}
else if(s[i].count==0)//判定机票是否售完
{
cout<<"对不起,你所选择的航班的机票已售完!\n";
break;
}
else if(s[i].count!=0&&s[i].count>=n)//判定机票数是否大于等于订票数
{
s[i].count=s[i].count-n;
u[m3].ucount1=n;
m3++;
cout<<"订票成功! ";
break;
}
else if(s[i].count<n)//判定机票数是否小于订票数
{
cout<<"对不起,你所选择的航班只剩"<<s[i].count<<"张机票\n";
cout<<"是否需要重新输入机票数?请输入y或n以回车键结束: ";//判定是否重新输入订票数
cin>>a;
}
}while(!strcmp(a,"y"));
cout<<"是否需要订其他航班的机票?请输入y或n以回车键结束: ";
cin>>a;
}while(!strcmp(a,"y"));//判定是否继续订票
cout<<"订票完毕!按回车键返回主菜单"<<endl;
for(int k=0;k<=m3;k++)//保存订单信息
{
outfile2<<u[k].uname<<" "<<u[k].unumber<<" "<<u[k].dnum<<" "<<u[k].dstartcity<<" "<<u[k].dovercity<<" "<<u[k].dtime<<" "<<u[k].dstarttime<<" "<<u[k].dovertime<<" "<<u[k].dprice<<" "<<u[k].ucount1;
}
for(int m5=0;m5<m;m5++)//保存航班信息
{
outfile3<<s[m5].num<<" "<<s[m5].start<<" "<<s[m5].over<<" "<<s[m5].time<<" "<<s[m5].starttime<<" "<<s[m5].overtime<<" "<<s[m5].price<<" "<<s[m5].zhekou<<" "<<s[m5].count<<endl;
}
u[m3].dname+=1;
getchar();
getchar();
loop6: Mframe();
}
void tuipiao()//定义退票函数
{
ofstream outfile4;
outfile4.open("hangban.txt",ios::out);
ofstream outfile5;
outfile5.open("message.txt",ios::out);
int m2,n,m1,n1;
char a[10];
do
{
string mnum;
cout<<"请输入你的证件号码:\n";
cin>>mnum;
for(int m=0;m<=m3;m++)
{
if(mnum==u[m].unumber)
{
cout<<"******************************"<<endl;
cout<<"*编号:"<<u[m].dname<<" *"<<endl;
cout<<"* "<<u[m].dstartcity<<"----"<<u[m].dnum<<"---->"<<u[m].dovercity<<" *"<<endl;
cout<<"* "<<u[m].dtime<<" "<<u[m].dstarttime<<" *"<<endl;
cout<<"* "<<u[m].dprice<<" *"<<endl;
cout<<"* "<<u[m].uname<<" *"<<endl;
cout<<"* "<<u[m].unumber<<" *"<<endl;
cout<<"******************************"<<endl;
goto loop4;
}
}
cout<<"未找到你的信息!!"<<endl;
goto loop5;
loop4:cout<<"信息输出完毕!"<<endl;
cout<<"请输入要退票的航班号:";
loop2:cin>>m2;//输入要退票的航班号
for(m1=0;m1<=m;m1++)
{
if(m2==s[m1].num)
{
i=m1;//记录航班在s[]数组中的位置
}
}
for(m1=0;m1<=m3;m1++)//u[]数组
{
if(m2==u[m1].dnum)n1=m1;goto loop1;
}
cout<<"请输入正确的的航班号:";
goto loop2;
loop1:cout<<"请输入您要退的机票数目: ";
loop3:cin>>n;//输入所退票数
if(n<=0)//判定票数是否有效
{cout<<"输入错误!至少需退1张机票。\n请重新输入: ";
goto loop3;}
else if(n>u[n1].ucount1)
{cout<<"输入错误!大于你的总票数。\n请重新输入:";
goto loop3;}
else
{
s[i].count=s[i].count+n;
u[m1].ucount1=u[m1].ucount1-n;
cout<<"退票成功! ";
}
loop5:cout<<"是否继续? 请键入y或n以回车键结束: ";//判定是否继续退票
cin>>a;
}while(!strcmp(a,"y"));//判定并跳出循环
for(int m5=0;m5<i;m5++) //保存航班
{
outfile4<<s[m5].num<<" "<<s[m5].start<<" "<<s[m5].over<<" "<<s[m5].time<<" "<<s[m5].starttime<<" "<<s[m5].overtime<<" "<<s[m5].price<<" "<<s[m5].zhekou<<" "<<s[m5].count<<endl;
}
for(int k=0;k<m3;k++)//保存订票信息
{
outfile5<<u[k].uname<<" "<<u[k].unumber<<" "<<u[k].dnum<<" "<<u[k].dstartcity<<" "<<u[k].dovercity<<" "<<u[k].dtime<<" "<<u[k].dstarttime<<" "<<u[k].dovertime<<" "<<u[k].dprice<<" "<<u[k].ucount1;
}
cout<<"退票完毕!按回车键返回主菜单"<<endl;
getchar();
Mframe();
}
void paixu()//定义排序函数
{
clock_t start, end;
start = clock();
quickSort(s, 0, i);
end = clock();
time1= end - start;
cout << "串行时间:" << time1 << endl;
cout<<"排序后的航班信息为:\n";
output();//显示排序后航班信息
cout<<"\n请按回车键返回上层菜单 ";
getchar();
getchar();
Mframe();
}
void quickSort(air A[], int first, int end)
{
int i = first, j = end;
air tmp;
if (first < end)
{
tmp = A[first];
while (i != j)
{
while (j > i&&A[j].num >= tmp.num)
j--;
A[i] = A[j];
while (i < j&&A[i].num <= tmp.num)
i++;
A[j] = A[i];
}
s[i] = tmp;
quickSort(A, first, i - 1);
quickSort(A, i + 1, end);
}
}
/*void paixu1()//定义从小到大排序函数
{
int k,j;
struct air t;
for(i=0;i<m;i++)
{
k=i;
for(j=i+1;j<m;j++)
if(s[k].num>s[j].num)
k=j;
if(i!=k)
{
t=s[k];
s[k]=s[i];
s[i]=t;
}
}
}
void paixu2()//定义从大到小排序函数
{
int k,j;
struct air t;
for(i=0;i<m;i++)
{
k=i;
for(j=i+1;j<m;j++)
if(s[k].num<s[j].num)
k=j;
if(i!=k)
{
t=s[k];
s[k]=s[i];
s[i]=t;
}
}
}*/
void mymessage() //我的信息
{
string mnum;
cout<<"请输入你的证件号码:\n";
cin>>mnum;
for(int m=0;m<=m3;m++)
{
if(mnum==u[m].unumber)
{
if(u[m].ucount1==0)goto loop3;
cout<<"************************************"<<endl;
cout<<"*编号:"<<u[m].dname<<" *"<<endl;
cout<<"* "<<u[m].dstartcity<<"----"<<u[m].dnum<<"---->"<<u[m].dovercity<<" *"<<endl;
cout<<"* "<<u[m].dtime<<" "<<u[m].dstarttime<<" *"<<endl;
cout<<"* "<<u[m].dprice<<" *"<<endl;
cout<<"* "<<u[m].uname<<" *"<<endl;
cout<<"* "<<u[m].unumber<<" *"<<endl;
cout<<"************************************"<<endl;
goto loop2;
}
}
loop3:cout<<"未找到你的信息!!"<<endl;
loop2:cout<<"信息输出完毕!"<<endl;
cout<<"按回车键返回上一页!";
getchar();
getchar();
Mframe();
}
void save()//定义保存函数
{
ofstream hfile;
hfile.open("hangban.txt",ios::out);
ofstream mfile;
mfile.open("message.txt",ios::out);
for(i=0;i<m;i++)//逐块保存数据
{
hfile<<s[i].num<<" "<<s[i].start<<" "<<s[i].over<<" "<<s[i].time<<" "<<s[i].starttime<<" "<<s[i].overtime<<" "<<s[i].price<<" "<<s[i].zhekou<<" "<<s[i].count<<endl;
}
hfile.close();
for(int k=0;k<m3;k++)//逐块保存数据
{
mfile<<u[k].uname<<" "<<u[k].unumber<<" "<<u[k].dnum<<" "<<u[k].dstartcity<<" "<<u[k].dovercity<<" "<<u[k].dtime<<" "<<u[k].dstarttime<<" "<<u[k].dovertime<<" "<<u[k].dprice<<" "<<u[k].ucount1;
}
mfile.close();
}
void merge()
{
int m = 0, n = 0, k;
for (k = 0; k < i; k++)
{
if (m < count_len2&&n < count_len1)
{
if (b[n].num <= c[m].num)
{
s[k] = b[n];
n++;
}
else
{
s[k] = c[m];
m++;
}
}
if (m == count_len2 || n == count_len1)
{
if (m == count_len2)
s[k] = c[m - 1];
else
s[k] = b[n - 1];
k++;
break;
}
}
if (n < count_len1)
{
int tem = count_len1 - n;
for (int p = 0; p < tem; p++)
{
s[k] = b[n];
n++;
k++;
}
}
else if (m < count_len2)
{
int tem = count_len2 - m;
for (int q = 0; q < tem; q++)
{
s[k] = c[m];
m++;
k++;
}
}
}
void jisubi()
{
clock_t start, end;
start = clock();
omp_set_num_threads(2);
#pragma omp parallel shared(b,c,count_len1,count_len2)
{
#pragma omp parallel sections
{
#pragma omp section
quickSort(b, 0, count_len1 - 1);
#pragma omp section
quickSort(c, 0, count_len2 - 1);
}
}
merge();
end = clock();
time2 = end - start;
cout << "并行时间:" << time2 << endl;
paixu();
}
6.6.2 执行结果截图
(1)小数据量验证正确性的执行结果
加速比:0
(2)大数据量获得较好加速比的执行结果
理论加速比:1.9
6.6.3 遇到的问题及解决方案
问题:
遇到的问题就是输入数据很少时,所需时间都为零或者加速比不明显。
分析:
由于电脑配置比较先进,运算能力很强。
解决方法:
加大数据量。