並行計算與多核多線程技術
課程報告
專業 軟件工程
班級 計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 遇到的問題及解決方案
問題:
遇到的問題就是輸入數據很少時,所需時間都爲零或者加速比不明顯。
分析:
由於電腦配置比較先進,運算能力很強。
解決方法:
加大數據量。