1. 程式人生 > >平行計算入門案例

平行計算入門案例

首先是cuda程式設計,分三步,把資料從記憶體拷貝進視訊記憶體,GPU進行計算,將結果從視訊記憶體拷貝回記憶體。

cuda-C程式氣泡排序案例:

#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>
#include <stdlib.h>

#define N 400
void random_ints(int *);

__global__ void myKernel(int *d_a)
{
	__shared__ int s_a[N]; //定義共享變數
	int tid = threadIdx.x;
	s_a[tid] = d_a[tid]; //每個執行緒搬運對應的資料到共享記憶體中
	__syncthreads(); //執行緒同步

	for (int i = 1; i <= N; i++) { //最多N次排序完成

		if (i % 2 == 1 && (2 * tid + 1) < N) { //奇數步
			if (s_a[2 * tid] > s_a[2 * tid + 1]) {
				int temp = s_a[2 * tid];
				s_a[2 * tid] = s_a[2 * tid+1];
				s_a[2 * tid + 1] = temp;
			}
		} 
		__syncthreads(); //執行緒同步
		if (i % 2 == 0 && (2 * tid + 2) < N ) { //偶數步
			if (s_a[2 * tid+1] > s_a[2 * tid + 2]) {
				int temp = s_a[2 * tid+1];
				s_a[2 * tid+1] = s_a[2 * tid + 2];
				s_a[2 * tid + 2] = temp;
			}
		}
		__syncthreads(); //執行緒同步		
	}
	d_a[tid] = s_a[tid]; //將排序結果搬回到Global Memory
}

int main()
{
	//定義變數
	int *a,*d_a;
	int size = N * sizeof(int);

	//Host端變數分配記憶體
	a = (int *)malloc(size); 
	//初始化待排序陣列
	random_ints(a);
	
	//Device端變數分配記憶體
	cudaMalloc((void **)&d_a, size);

	//將資料從Host端拷貝到Device端
	cudaMemcpy(d_a, a, size, cudaMemcpyHostToDevice);

	//呼叫核函式
	myKernel<<<1, N >>> (d_a);

	//將資料從Device端拷貝到Host端
	cudaMemcpy(a, d_a, size, cudaMemcpyDeviceToHost);

	//列印排序結果
	for (int i = 0; i < N; i++) {
		printf("%d ", a[i]);
	}

	//釋放記憶體
	free(a); 
	cudaFree(d_a); 
	return 0;
}
void random_ints(int *a)
{
	if (!a) { //異常判斷
		return;
	}
	for (int i = 0; i < N; i++) {
		a[i] = rand() % N; //產生0-N之間的隨機整數
	}
}

然後openmp只需要在迴圈耗時的地方加上一句話即可。

還有就是MPI使用6個基本函式即可。

MPI初始化:通過MPI_Init函式進入MPI環境並完成所有的初始化工作

int MPI_Init( int *argc, char * * * argv )

MPI結束:通過MPI_Finalize函式從MPI環境中退出

int MPI_Finalize(void)

獲取程序的編號:呼叫MPI_Comm_rank函式獲得當前程序在指定通訊域中的編號,將自身與其他程式區分

int MPI_Comm_rank(MPI_Comm comm, int *rank)

獲取指定通訊域的程序數:呼叫MPI_Comm_size函式獲取指定通訊域的程序個數,確定自身完成任務比例

int MPI_Comm_size(MPI_Comm comm, int *size)

訊息傳送:MPI_Send函式用於傳送一個訊息到目標程序

int MPI_Send(void *buf, int count, MPI_Datatype dataytpe, int dest, int tag, MPI_Comm comm) 

訊息接受:MPI_Recv函式用於從指定程序接收一個訊息

int MPI_Recv(void *buf, int count, MPI_Datatype datatyepe,int source, int tag, MPI_Comm comm, MPI_Status *status)

圓周率計算案例:

【OpenMP_PI】
#include <omp.h>
#include<stdio.h>
#include<time.h>

#define NUM_THREADS 8
double seriel_pi();
double parallel_pi();
static long num_steps = 1000000000;
double step;
void main()
{
	clock_t start; float time; double pi;
	start = clock();
	pi=seriel_pi();
	time = (float)(clock() - start);
	printf("Seriel:PI=%.5f  time=%.1f\n", pi,time);
	start = clock();
	pi = parallel_pi();
	time = (float)(clock() - start);
	printf("Parallel:PI=%.5f  time=%.1f\n", pi, time);
}
double parallel_pi() {
	int i; double x, pi, sum = 0.0;
	step = 1.0 / (double)num_steps;
	omp_set_num_threads(NUM_THREADS);
#pragma omp parallel for private(x) reduction (+:sum)
	for (i = 0; i< num_steps; i++) {
		x = (i + 0.5)*step;
		sum += 4.0 / (1.0 + x*x);
	}
	pi = sum * step;
	return pi;
}
double seriel_pi() {
	double x, pi, sum = 0.0;
	step = 1.0 / (double)num_steps;
	for (int i = 0; i< num_steps; i++) {
		x = (i + 0.5)*step;
		sum = sum + 4.0 / (1.0 + x*x);
	}
	pi = step * sum;
	return pi;
}

【Cuda_PI】
#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>
#include<stdlib.h>
#include<time.h>

double seriel_pi();
#define B 128     //塊的個數
#define T 512		//每個塊中的執行緒數
#define N 1000000000   //劃分的step個數


__global__ void reducePI1(double *d_sum) {
	

	int gid = threadIdx.x + blockIdx.x*blockDim.x;//執行緒索引

	__shared__ double s_sum[T];//長度為block執行緒數

	s_sum[threadIdx.x] = 0.0; //初始化

	double x;

	while (gid < N) { 
		x = (gid + 0.5)/N;//當前x值
		s_sum[threadIdx.x] += 4.0 / (1.0 + x*x);//對應的y值
		gid += blockDim.x*gridDim.x; //若匯流排程數不足時,進行累加
		__syncthreads();
	}

	for (int i = (blockDim.x >> 1); i>0; i >>= 1) { //歸約到s_sum[0]
		if (threadIdx.x<i) {
			s_sum[threadIdx.x] += s_sum[threadIdx.x + i];
		}
		__syncthreads();
	}


	if (threadIdx.x == 0) {
		d_sum[blockIdx.x] = s_sum[0]; //每個block儲存自己block的歸約值
	}
}

__global__ void reducePI2(double *d_sum) {

	int id = threadIdx.x;

	__shared__ double s_pi[B];


	s_pi[id] = d_sum[id]; //將資料拷貝到共享記憶體區
	__syncthreads();


	for (int i = (blockDim.x >> 1); i>0; i >>= 1) { //歸約到s_pi[0]
		if (id < i) {
			s_pi[id] += s_pi[id + i];  
		}
		__syncthreads();
	}

	if (id == 0) {
		d_sum[0] = s_pi[0]/N;

	}
}

int main()
{
	//定義變數
	double *pi, *d_sum;
	clock_t start; float time;

	//Host端變數分配記憶體
	pi = (double *)malloc(sizeof(double));
	//Device端變數分配記憶體
	cudaMalloc((void **)&d_sum, B*sizeof(double));

	//序列計算
	start = clock();
	pi[0] = seriel_pi();
	time = (float)(clock() - start);
	printf("Seriel:PI=%.5f  time=%.1f\n", pi[0], time);

	//平行計算
	start = clock();
	//呼叫核函式
	reducePI1 <<<B, T >>> (d_sum);
	reducePI2 <<<1, B >>> (d_sum);

	//將資料從Device端拷貝到Host端
	cudaMemcpy(pi, d_sum, sizeof(double), cudaMemcpyDeviceToHost);
	time = (float)(clock() - start);
	printf("Parallel:PI=%.5f  time=%.1f\n", pi[0], time);


	//釋放記憶體
	free(pi);
	cudaFree(d_sum);
	return 0;
}
double seriel_pi() {
	double x, pi,step, sum = 0.0;
	step = 1.0 / (double)N;
	for (int i = 0; i< N; i++) {
		x = (i + 0.5)*step;
		sum = sum + 4.0 / (1.0 + x*x);
	}
	pi = step * sum;
	return pi;
}

【MPI_PI】
#include<stdio.h>
#include "mpi.h"
#include<math.h>
#pragma comment (lib, "msmpi.lib") 


int main(int argc, char *argv[]) {
	int my_rank, num_procs;
	int i, n = 100000000;
	double sum=0.0, step, x, mypi, pi;
	double start = 0.0, stop = 0.0;

	MPI_Init(&argc, &argv);          //初始化環境
	MPI_Comm_size(MPI_COMM_WORLD, &num_procs);   //獲取並行的程序數
	MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);     //當前程序在所有程序中的序號

	start = MPI_Wtime();
	step = 1.0 / n;
	for (i = my_rank; i<n; i += num_procs) {
		x = step*((double)i + 0.5);
		sum += 4.0 / (1.0 + x*x);
	}
	mypi = step*sum;

	MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);    //由程序0進行歸約,把每個程序計算出來的mypi進行相加(MPI_SUM),賦給pi
	if (my_rank == 0) {
		printf("PI is %.20f\n", pi);
		stop = MPI_Wtime();
		printf("Time: %f\n", stop - start);
		fflush(stdout);
	}
	MPI_Finalize();
	return 0;
}

序列


並行



相關推薦

平行計算入門案例

首先是cuda程式設計,分三步,把資料從記憶體拷貝進視訊記憶體,GPU進行計算,將結果從視訊記憶體拷貝回記憶體。cuda-C程式氣泡排序案例:#include "cuda_runtime.h" #include "device_launch_parameters.h" #i

GPU平行計算入門1——背景知識

專有名詞: GPGPU 通用圖形處理器 (英語:General-purpose computing on graphics processing units,簡稱GPGPU或GP²U),利用處理圖形任務的圖形處理器來計算原本由中央處理器處理的通用計算任務,這些

【python 入門案例】hi finance python入門:餘額寶計算案例

一、計算餘額寶年化利率 抄寫強哥的代買,並根據自己的理解做修改 程式碼如下: #simport math from decimal import * #import decimal # 改進版roud函式,可以四捨五入保留小數,返回 字串 def new_round(

Scrapy 爬蟲框架入門案例詳解

tin mon setting 爬蟲框架 finished perror project 原因 create 歡迎大家關註騰訊雲技術社區-博客園官方主頁,我們將持續在博客園為大家推薦技術精品文章哦~ 作者:崔慶才 Scrapy入門 本篇會通過介紹一

JavaScript入門案例

tran ext ring ble .org lis rip xhtml date <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/

SpringMVC入門案例:HelloWorld

javax file tar view 過程 name res location page 本文摘自:http://www.cnblogs.com/bigdataZJ/p/springmvc1.html 軟件參數   Eclipse:Mars.1 Release (

人工智能、機器學習和認知計算入門指南

不遠 要素 人工 算法 網絡拓撲 界面 分布 target 用戶 幾千年來,人們就已經有了思考如何構建智能機器的想法。從那時開始,人工智能 (AI) 經歷了起起落落,這證明了它的成功以及還未實現的潛能。如今,隨時都能聽到應用機器學習算法來解決新問題的新聞。從癌癥檢測和預測到

quarz入門案例

應用 創建 bstr -o 開發者 exception java應用 throws 執行 介紹 Quartz框架是一個全功能、開源的任務調度服務,可以集成幾乎任何的java應用程序—從小的單片機系統到大型的電子商務系統。Quartz可以執行上千上萬的任務調度。

MyBatis學習(一)簡介及入門案例

結果集 提交 ace 支持 nag 實例 exce 空間 cti 1.什麽是MyBatis?   MyBatis是一個支持普通SQL查詢,存儲過程,和高級映射的優秀持久層框架。MyBatis去掉了幾乎所有的JDBC代碼和參數的手工設置以及對結果集的檢索封裝。MyBatis可

k8s入門案例

ice con art get install cas replicat yum 火墻 1、關閉CentOS自帶的防火墻服務: systemctl disable firewalld systemctl stop firewalld 2、安裝etcd和K

Mybatis 入門案例分享

java mybatis 本文分享一下,Mybatis的一些入門案例;為什麽不用JDBC方式來操作數據庫,而使用類似於Mybatis的框架呢?1、 數據庫鏈接創建、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用數據庫鏈接池可解決此問題。解決:在SqlMapConfig.xml中配置數據鏈接池,使

Python爬蟲Scrapy(二)_入門案例

efi with 進入 中繼 reload tle 下載 摘要 excel打開 本章將從案例開始介紹python scrapy框架,更多內容請參考:python學習指南 入門案例 學習目標 創建一個Scrapy項目 定義提取的結構化數據(Item) 編寫爬取網站的S

golang入門案例之SOCKET

int div 進行 lec ont func 轉換 exit oca //服務端代碼package main import ( "fmt" "net" "log" "os" "encoding/binary" ) func main() { //建立s

Elasticsearch快速入門案例

nod esp 每次 行高 dice climb 添加 last 我們 寫在前面的話:讀書破萬卷,編碼如有神-------------------------------------------------------------------- 參考內容:   《Elast

redis主從復制入門案例

服務器 過程 擁有 新的 redis 成功 指定 復制 center 主從復制 特點: 1.master可以擁有多個slave 2.多個slave可以連接同一個master外,還可以連接到其他slave 3.主從復制不會阻塞master,在同步數據時,master可以繼續處

2018年最新Linux雲計算入門學習路線圖

Linux Linux運維 近年來,Linux在技術行業裏的重要性越來越高,成為了IT從業者的必備技能之一,據統計,Linux相關崗位增長達到了驚人的24%。市場需求擴大後Linux技術人員的薪資也一路上升,1-3年Linux運維工程師的平均薪資上升了13%。因為幾年來很多人都選擇轉行從事Linux運

Struts2入門案例

pattern 入門 tsp ack namespace text demo 自動 org 本文用的是Intellij IDEA開發工具,struts2版本是struts-2.3.24,官網最新的是2.5,和2.3有些區別。 官網下載地址:https://struts.ap

CMake系列之二:入門案例-單個源文件

bubuko 源文件 註釋 http 編寫 AD 源碼 power 比較 編寫一個源碼文件 如下 1 #include<stdio.h> 2 #include<stdlib.h> 3 4 double power(double

計算入門課程,雲計算學習哪裏好?

雲計算雲計算學習哪裏好?這個問題實在太簡單了。如果說×××教育的老師推薦×××教育,那麽大家可能會覺得這是“老王賣瓜,自賣自誇”。那麽,不如這樣,我們把×××教育地雲計算教學大綱給出來,大家對比一下,自然就知道雲計算學習哪裏好了。 ×××教育獨家開發了“2018×××Linux雲計算架構師+Python運維開

計算學習哪裏好?雲計算入門課程

雲計算雲計算是是一種服務的使用和交付模式,通常涉及經過網絡來提供動態易擴展且經常是虛擬化的資源。以前的網絡拓撲圖中往往用雲來表示ISP網絡,後來也用來表示網絡和底層基礎設施的抽象。因此,雲計算甚至可以讓你體驗每秒數萬次的運算能力,擁有這麽強大的計算能力可以進行試驗模擬、大數據分析和市場發展趨勢。用戶用自己的電