當前位置:首頁 » 編程軟體 » 並行編程模型

並行編程模型

發布時間: 2022-03-07 18:50:20

① 並行程序設計的類別

目前並行編程類型逐漸匯聚於兩類:用於PVP,SMP和DSW的共享變數的單地址空間模型和用於MPP和機群的消息傳遞的多地址空間模型.
並行編程模型逐漸匯聚於三類標准模型:數據並行(如:HPF),消息傳遞(如:MPI和PVM),和共享變數(如OpenMp).
現在人們希望高性能的並行機應是 具有單一系統映像的巨大的工作站,使得很多用戶都能利用增強處理能力和儲存容量來運行多個串列作業,這就是所謂的串列程序並行系統SPPS.
當我們在實際的並行機上設計並行程序時,絕大部分均是採用擴展Fortran和C語言的辦法,目前有三種擴展的辦法:一是庫函數法:除了串列語言所包含的庫函數外,一組新的支持並行性和交互操作的庫函數(如MPI消息傳遞庫和POSIXPthreads多線程庫)引入到並行程序設計中。二是新語言結構法:採用某些新的語言結構來幫助並行程序設計以支持並行性和交互操作(如Fortran 90 中的聚集數組操作); 三是編譯制導法:程序設計語言保持不變,但是將稱之為編譯制導的格式注釋引入到並行程序中.

② 並行程序設計的並行程序設計:

對於所希望的應用,很多並行代碼似乎不存在的;即使有,也常不能用於用戶的並行機上.因為並行代碼原來都是為不同的並行結構寫的.
其原因是:①並行程序設計不但包含了串列程序設計,而且還包含了更多的富有挑戰性的問題;②串列程序設計僅有一個普遍被接受的馮*諾依曼模型,而並行計算模型雖有好多,但沒有一個被共同認可;③並行程序設計對環境工具的要求遠比串列程序設計先進得多;④串列程序設計比較適合於自然習慣,且人們在過去積累了大量的編程知識和寶貴的軟體財富.
它的問題是:至今並行演算法範例不能被很好地理解和廣泛地接受;並行程序設計是建立在不同的計算模型上的,而它們沒有能像馮*諾依曼模型那樣被普遍的接受和認可.絕大部分被使用的並行程序設計語言都是Fortran和C的推廣,他們都不能夠充分地表達不同並行結構的特點,既不成熟也不通用.並行程序設計工具依賴於具體的並行結構和計算機代的更迭,既不通用也不穩定,在某個並行平台上開發的並行程序很難移植到別的或將來的並行機上.

③ 並行計算模型的C3模型

C3模型假定處理機不能同時發送和接收消息,它對超步的性能分析分為兩部分:計算單元CU,依賴於本地計算量;通信單元COU,依賴與處理機發送和接收數據的多少、消息的延遲及通信引起的擁擠量。該模型考慮了兩種路由(存儲轉發路由和蟲蝕尋徑路由)和兩種發送/接收原語(阻塞和無阻塞)對COU的影響。 (1)用Cl和Cp來度量網路的擁擠對演算法性能的影響;
(2)考慮了不同路由和不同發送或接收原語對通信的影響;
(3)不需要用戶指定調度細節,就可以評估超步的時間復雜性;
(4)類似於H-PRAM模型的層次結構,C3模型給編程者提供了K級路由演算法的思路,即系統被分為K級子系統,各級子系統的操作相互獨立,用超步代替了H-PRAM中的Sub PRAM進行分割。 (1)Cl度量的前題假設為同一通信對中的2個處理機要分別位於網路對分後的不同子網路內;
(2)模型假設了網路帶寬等於處理機帶寬,這影響了正確描述可擴展系統;
(3)在K級演算法中,處理機間順序可以由多種排列,但C3模型不能區分不同排列的難易程度。

④ MPI並行程序設計實例教程的目錄

第1章MPI並行環境及編程模型
1.1MPICH2環境及安裝和測試
1.1.1編譯及安裝
1.1.2配置及驗汪
1.1.3應用程序的編譯、鏈接
1.1.4運行及調試
1.1.5MPD中的安全問題
1.2MPI環境編程模型
1.2.1並行系統介紹
1.2.2並行編程模式
1.2.3MPI程序工作模式
1.3MPI消息傳遞通信的基本概念
1.3.1消息
1.3.2緩沖區
1.3.3通信子
1.3.4進樣號和l進程紕
1.3.5通價脅議
1.3.6隱形對象
第2章點到點通信
2.1阻糍通信
2.1.1標准通信模式
2.1.2緩沖通信模式
2.1.3就緒通信模式
2.1.4同步通信模式
2.1.5小結
2.2非阻塞通信
2.2.1通信結束測試
2.2.2非重復的非阻塞通信
2.2.3可醺復的非阻塞通信
2.2.4Probe和Cancel
2.3組合發送接收
2.3.1MPl_Send,MPI_RecvoMPl_Sendreev
2.3.2MPI_Bsend←→MPl_Sendrecv
2.3.3MPI_Rsend←→MPI_Sendrecv
2.3.4MPl_Ssend←→MPl_Sendrecv
2.3.5MPl_lsend←→MP1一Sendrecv
2.3.6MPl_Ibsend←→MPI_Sendrecv
2.3.7MPI_Irsend←→MPI_Sendrecv
2.3.8MPl_Issend,MPI_Irecv←→MPI_Sendrecv
2.3.9MPISend_init←→MPl_Sendrecv
2.3.10MPI一Bsendjinit←→MPl_Sendrecv
2.3.11MPI_Rsend_init←→MPI_Sendrecv
2.3.12MPl_Ssend_init,MPl_Recv_init←→MPl_Sendrecv
2.4點到點通信總結
2.4.1關於預防死鎖
2.4.2關於阻塞與非阻塞、同步與非同步
2.4.3關於操作的執行順序及「公平性」
第3章組與通信子
3.1簡介
3.2組管理API
3.2.1組的構建及取消
3.2.2訪問組的相關信息和屬性
3.3組問通信
3.3.1創建與取消
3.3.2訪問通信子信息
3.4組間通信
3.4.1訪問函數
3.4.2構造和取消函數
3.5屬性
3.5.1創建及釋放屬性操作
3.5.2訪問屬性操作
3.5.3設置及刪除屬性操作
3.5.4命名通信子對象
3.6錯誤處理
3.7組及通信子的小結
第4章集合通信
4.11←→N
4.1.1MPI_Bcast
4.1.2MPI_Scatter/MPI_Scatterv
4.2N←→1
4.2.1MPl_Gather/MPI_Gatherv
4.2.2MPI_Rece
4.3N←→N
4.3.1MPI_Allgather/MPI_Allgatherv.
4.3.2MPI_Allrece
4.3.3MPl_Recescatter
4.3.4MPI_Alltoall/MPIAlltoallv/MPI_Alltoallw
4.3.5MPI_Scan/MPI_Exscan
4.4同步操作--MPI_Barrier
第5章數據類型
5.1類型圖
5.2與數據類型相關的API函數
5.2.1創建
5.2.2訪問
5.2.3注冊與取消
5.3數據類型在通信函數緩沖區的構成
5.4數據類型的屬性
5.4.1屬性創建與釋放
5.4.2屬性操作
5.4.3復制數據類型
5.4.4類型屬性舉例
5.4.5數據類型命名
5.5數據類型的析構
5.5.1獲取創建數據類型MPI函數所使用參數數量信息
5.5.2獲取創建數據類型MPI函數所使用實際參數信息
5.5.3示例
5.6打包/解包
第6章進程拓撲
第7章動態進程管理
第8章單向通信/遠端內存訪問
第9章並行I/O
第10章MPI與外部環境的信息交互
第11章MPE
參考文獻
……

⑤ 如何選擇合適的多線程模型

本篇文章小編為大家介紹,非同步/多線程/任務/並行編程之一:如何選擇合適的多線程模型?需要的朋友參考下

非同步、多線程、任務、並行編程之一:選擇合適的多線程模型
本篇概述:
@FCL4.0中已經存在的線程模型,以及它們之間異同點;
@多線程編程模型的選擇。

http://www.jb51.net/article/35903.htm

⑥ 從並行計算的角度對比,MPI 與 OpenMP 有什麼區別

OpenMP和MPI是並行編程的兩個手段,對比如下:

OpenMP:線程級(並行粒度);共享存儲;隱式(數據分配方式);可擴展性差。

MPI:進程級;分布式存儲;顯式;可擴展性好。OpenMP採用共享存儲,意味著它只適應於SMP,DSM機器,不適合於集群。MPI雖適合於各種機器,但它的編程模型復雜。

需要分析及劃分應用程序問題,並將問題映射到分布式進程集合。需要解決通信延遲大和負載不平衡兩個主要問題。

延伸論述:

我認為,要理解OpenMP和MPI,首先要有一些操作系統知識和系統編程基礎——OpenMP對應的實際上是單進程多線程的並發編程模型,可以將一個單線程的程序按for循環拆分成多線程——相當於pthread_create。

對於同一個進程的多個線程來說,由於它們只是獨占自己的棧內存,堆內存是共享的,因此數據交換十分地容易,直接通過共享變數就可以進行交換,編程模型非常簡單易用,並且對於操作系統來說,線程的上下文切換成本也比進程低很多。

然而另一方面,由於線程不能脫離進程獨立存在,而一個進程不能存在於多台機器上,所以OpenMP只適用於擁有多個CPU核心的單台電腦。並且多線程編程存在臨界區(Critical Section),需要你自己去加鎖,解決Race Condition問題,否則的話很容易導致不可預知的後果。

而MPI則是多進程的並發編程模型,相當於你自己調用fork——每一個進程的內存地址空間都是獨立的,它們彼此之間幾乎什麼都不共享,只能通過進程間通信(IPC)來交換彼此的數據,因此編程難度明顯要大很多。

MPI有一個非常顯著的優點,那就是對於一個分布式系統來說,進程是可以在分布式系統的每一台電腦之間轉移的,因此對於擁有多台電腦的分布式系統來說,其並發性要明顯好於OpenMP。

⑦ 並行計算模型的LogP模型

根據技術發展的趨勢,20世紀90年代末和未來的並行計算機發展的主流之一是巨量並行機,即MPC(Massively Parallel Computers),它由成千個功能強大的處理器/存儲器節點,通過具有有限帶寬的和相當大的延遲的互連網路構成。所以我們建立並行計算模型應該充分考慮到這個情況,這樣基於模型的並行演算法才能在現有和將來的並行計算機上有效的運行。根據已有的編程經驗,現有的共享存儲、消息傳遞和數據並行等編程方式都很流行,但還沒有一個公認的和占支配地位的編程方式,因此應該尋求一種與上面的編程方式無關的計算模型。而根據現有的理論模型,共享存儲PRAM模型和互連網路的SIMD模型對開發並行演算法還不夠合適,因為它們既沒有包含分布存儲的情況,也沒有考慮通信和同步等實際因素,從而也不能精確的反映運行在真實的並行計算機上的演算法的行為,所以,1993年D.Culer等人在分析了分布式存儲計算機特點的基礎上,提出了點對點通信的多計算機模型,它充分說明了互聯網路的性能特性,而不涉及到具體的網路結構,也不假定演算法一定要用現實的消息傳遞操作進行描述。
LogP模型是一種分布存儲的、點到點通信的多處理機模型,其中通信網路由4個主要參數來描述:
(1)L(Latency) 表示源處理機與目的處理機進行消息(一個或幾個字)通信所需要的等待或延遲時間的上限,表示網路中消息的延遲。
(2)o(overhead)表示處理機准備發送或接收每個消息的時間開銷(包括操作系統核心開銷和網路軟體開銷),在這段時間里處理不能執行其它操作。
(3)g(gap)表示一台處理機連續兩次發送或接收消息時的最小時間間隔,其倒數即微處理機的通信帶寬。
(4)P(Processor)處理機/存儲器模塊個數
假定一個周期完成一次局部操作,並定義為一個時間單位,那麼,L,o和g都可以表示成處理器周期的整數倍。 (1)抓住了網路與處理機之間的性能瓶頸。g反映了通信帶寬,單位時間內最多有L/g個消息能進行處理機間傳送。
(2)處理機之間非同步工作,並通過處理機間的消息傳送來完成同步。
(3)對多線程技術有一定反映。每個物理處理機可以模擬多個虛擬處理機(VP),當某個VP有訪問請求時,計算不會終止,但VP的個數受限於通信帶寬和上下文交換的開銷。VP受限於網路容量,至多有L/g個VP。
(4)消息延遲不確定,但延遲不大於L。消息經歷的等待時間是不可預測的,但在沒有阻塞的情況下,最大不超過L。
(5)LogP模型鼓勵編程人員採用一些好的策略,如作業分配,計算與通信重疊以及平衡的通信模式等。
(6)可以預估演算法的實際運行時間。 (1)對網路中的通信模式描述的不夠深入。如重發消息可能占滿帶寬、中間路由器緩存飽和等未加描述。
(2)LogP模型主要適用於消息傳遞演算法設計,對於共享存儲模式,則簡單地認為遠地讀操作相當於兩次消息傳遞,未考慮流水線預取技術、Cache引起的數據不一致性以及Cache命中率對計算的影響。
(3)未考慮多線程技術的上下文開銷。
(4)LogP模型假設用點對點消息路由器進行通信,這增加了編程者考慮路由器上相關通信操作的負擔。

⑧ 請問多線程並行編程中用到的pthread.h文件,上哪兒下載

到http://sourceware.org/pthreads-win32/上可以查看pthread的相關介紹和信息,也可以下載pthread.h頭文件和庫文件。

下載文件夾ftp://sourceware.org/pub/pthreads-win32/

最新的dll,庫,頭文件和管理文檔 DLLs, LIBs, header files, and admin documentation

ftp://sourceware.org/pub/pthreads-win32/dll-latest/

⑨ MPI是用於什麼系統的並行編程模型

openmp和mpi原理:openmp一般用於多核並行,

全是一種並行編程框架,mpi是一種基於消息的進程間通信機制,可以跨越多機。實際中,一般俠義的mpi配合調器一起完成

⑩ 單核cpu的並行過程,求解答

CPU並行編程概述
並行編程的演化
一個自然而然的問題是:為什麼要用並行編程?在20世紀70年代、80年代甚至90年代的一部分時間里,我們對單線程編程(或者稱為串列編程)非常滿意。你可以編寫一個程序來完成一項任務。執行結束後,它會給你一個結果。任務完成,每個人都會很開心!雖然任務已經完成,但是如果你正在做一個每秒需要數百萬甚至數十億次計算的粒子模擬,或者正在對具有成千上萬像素的圖像進行處理,你會希望程序運行得更快一些,這意味著你需要更快的CPU。

在2004年以前,CPU製造商IBM、英特爾和AMD都可以為你提供越來越快的處理器,處理器時鍾頻率從16 MHz、20 MHz、66 MHz、100 MHz,逐漸提高到200 MHz、333 MHz、466 MHz⋯⋯看起來它們可以不斷地提高CPU的速度,也就是可以不斷地提高CPU的性能。但到2004年時,由於技術限制,CPU速度的提高不能持續下去的趨勢已經很明顯了。這就需要其他技術來繼續提供更高的性能。CPU製造商的解決方案是將兩個CPU放在一個CPU內,即使這兩個CPU的工作速度都低於單個CPU。例如,與工作在300 MHz速度上的單核CPU相比,以200 MHz速度工作的兩個CPU(製造商稱它們為核心)加在一起每秒可以執行更多的計算(也就是說,直觀上看2×200 > 300)。

聽上去像夢一樣的「單CPU多核心」的故事變成了現實,這意味著程序員現在必須學習並行編程方法來利用這兩個核心。如果一個CPU可以同時執行兩個程序,那麼程序員必須編寫這兩個程序。但是,這可以轉化為兩倍的程序運行速度嗎?如果不能,那我們的2×200 > 300的想法是有問題的。如果一個核心沒有足夠的工作會怎麼樣?也就是說,只有一個核心是真正忙碌的,而另一個核心卻什麼都不做?這樣的話,還不如用一個300 MHz的單核。引入多核後,許多類似的問題就非常突出了,只有通過編程才能高效地利用這些核心。

核心越多,並行性越高
程序員不能簡單地忽略CPU製造商每年推出的更多數量的核心。2015年,英特爾在市場上推出8核台式機處理器i7-5960X[11]和10核工作站處理器,如Xeon E7-8870 [14]。很明顯,這種多核狂熱在可預見的未來會持續下去。並行編程從2000年年初的一種奇異的編程模型轉變為2015年唯一被接受的編程模型。這種現象並不局限於台式電腦。在移動處理器方面,iPhone和Android手機都有2個或4個核。預計未來幾年,移動領域的核心數量將不斷增加。

那麼,什麼是線程?要回答這個問題,讓我們來看看8核INTEL CPU i7-5960X [11]。 INTEL的文檔說這是一個8C/16T CPU。換句話說,它有8個核心,但可以執行16個線程。你也許聽到過並行編程被錯誤地稱為多核編程。正確的術語應該是多線程編程。這是因為當CPU製造商開始設計多核架構時,他們很快意識到通過共享一些核心資源(如高速緩存)來實現在一個核心中同時執行兩項任務並不困難。

類比1.1:核心與線程

圖1-1顯示了兩個兄弟Fred和Jim,他們是擁有兩台拖拉機的農民。每天,他們開車從農舍到椰子樹所在的地方,收獲椰子並把它們帶回農舍。他們用拖拉機內的錘子來收獲(處理)椰子。整個收獲過程由兩個獨立但有序的任務組成,每個任務需要30秒:任務1是從拖拉機走向椰子樹,每次帶回1顆椰子。任務2是用錘子敲碎(處理)它們,並將它們存放在拖拉機內。Fred每分鍾可以處理1顆椰子,而Jim每分鍾也可以處理1顆椰子。綜合起來,他們倆每分鍾可以處理2顆椰子。

一天,Fred的拖拉機發生了故障。他把拖拉機留在修理廠,並把椰子錘忘在了拖拉機內。回到農舍的時候已經太遲了,但他們仍然有工作要做。只使用Jim的拖拉機和裡面的1把椰子錘,他們還能每分鍾處理2顆椰子嗎?

核心與線程
讓我們來看看圖1-1中描述的類比1.1。如果收獲1顆椰子需要完成兩個連續的任務(我們將它們稱為線程):線程1從樹上摘取1顆椰子並花費30秒將它帶回拖拉機,線程2花費30秒用拖拉機內的錘子敲碎(處理)該椰子,這樣可以在60秒內收獲1顆椰子(每分鍾1顆椰子)。如果Jim和Fred各自都有自己的拖拉機,他們可以簡單地收獲兩倍多的椰子(每分鍾2顆椰子),因為在收獲每顆椰子時,他們可以共享從拖拉機到椰子樹的道路,並且他們各自擁有自己的錘子。

在這個類比中,一台拖拉機就是一個核心,收獲一顆椰子就是針對一個數據單元的程序執行。椰子是數據單元,每個人(Jim、Fred)是一個執行線程,需要使用椰子錘。椰子錘是執行單元,就像核心中的ALU一樣。該程序由兩個互相依賴的線程組成:在線程1執行結束之前,你無法執行線程2。收獲的椰子數量意味著程序性能。性能越高,Jim和Fred銷售椰子掙的錢就越多。可以將椰子樹看作內存,你可以從中獲得一個數據單元(椰子),這樣在線程1中摘取一顆椰子的過程就類似於從內存中讀取數據單元。

並行化更多的是線程還是核心
現在,讓我們看看如果Fred的拖拉機發生故障後會發生什麼。過去他們每分鍾都能收獲兩顆椰子,但現在他們只有一台拖拉機和一把椰子錘。他們把拖拉機開到椰子樹附近,並停在那兒。他們必須依次地執行線程1(Th1)和線程2(Th2)來收獲1顆椰子。他們都離開拖拉機,並在30秒內走到椰子樹那兒,從而完成了Th1。他們帶回挑好的椰子,現在,他們必須敲碎椰子。但因為只有1把椰子錘,他們不能同時執行Th2。Fred不得不等Jim先敲碎他的椰子,並且在Jim敲碎後,他才開始敲。這需要另外的30+30秒,最終他們在90秒內收獲2顆椰子。雖然效率不如每分鍾2顆椰子,但他們的性能仍然從每分鍾1顆提升至每分鍾1.5顆椰子。

收獲一些椰子後,Jim問了自己一個問題:「為什麼我要等Fred敲碎椰子?當他敲椰子時,我可以立即走向椰子樹,並摘獲下1顆椰子,因為Th1和Th2需要的時間完全相同,我們肯定不會遇到需要等待椰子錘空閑的狀態。在Fred摘取1顆椰子回來的時候,我會敲碎我的椰子,這樣我們倆都可以是100%的忙碌。」這個天才的想法讓他們重新回到每分鍾2顆椰子的速度,甚至不需要額外的拖拉機。重要的是,Jim重新設計了程序,也就是線程執行的順序,讓所有的線程永遠都不會陷入等待核心內部共享資源(比如拖拉機內的椰子錘)的狀態。正如我們將很快看到的,核心內部的共享資源包括ALU、FPU、高速緩存等,現在,不要擔心這些。

我在這個類比中描述了兩個配置場景,一個是2個核心(2C),每個核心可以執行一個單線程(1T);另一個是能夠執行2個線程(2T)的單個核心(1C)。在CPU領域將兩種配置稱為2C/2T與lC/2T。換句話說,有兩種方法可以讓一個程序同時執行2個線程:2C/2T(2個核心,每個核心都可以執行1個線程—就像Jim和Fred的兩台單獨的拖拉機一樣)或者lC/2T(單個核心,能夠執行2個線程—就像Jim和Fred共享的單台拖拉機一樣)。盡管從程序員的角度來看,它們都意味著具有執行2個線程的能力,但從硬體的角度來看,它們是非常不同的,這要求程序員充分意識到需要共享資源的線程的含義。否則,線程數量的性能優勢可能會消失。再次提醒一下:全能的INTEL i7-5960X [11] CPU是8C/l6T,它有8個核心,每個核心能夠執行2個線程。

圖1-2顯示了三種情況:a)是具有2個獨立核心的2C/2T情況;b)是具有糟糕編程的1C/2T情況,每分鍾只能收獲1.5顆椰子;c)是對椰子錘的需求永遠不會同時發生的順序正確版本,每分鍾可以收獲2顆椰子。

核心資源共享的影響
Jim為自己的發現感到自豪,他們的速度提高到每分鍾2顆椰子,Jim希望繼續創造一些方法來用一台拖拉機完成更多的工作。一天,他對Fred說:「我買了一把新的自動椰子錘,它在10秒內就能敲碎1顆椰子。」他們對這一發現非常滿意,立即出發並將拖拉機停在椰子樹旁。這次他們知道在開始收獲前必須先做好計劃⋯⋯

Fred問道:「如果我們的Th1需要30秒,而Th2需要10秒,並且我們唯一需要共享資源的任務是Th2(椰子錘),我們應該如何收獲椰子?」答案對他們來說很清楚:唯一重要的是線程的執行順序(即程序的設計),應確保他們永遠不會遇到兩人同時執行Th2並需要唯一的椰子錘(即共享核心資源)的情況。換句話說,它們的程序由兩個互相依賴的線程組成:Th1需要30秒,並且不需要共享(內存)資源,因為兩個人可以同時步行到椰子樹。Th2需要10秒並且不能同時執行,因為他們需要共享(核心)資源:椰子錘。由於每顆椰子需要30+10=40秒的總執行時間,他們能夠期望的最好結果是40秒收獲2顆椰子,如

圖1-2 d所示。如果每個人都按順序執行Th1和Th2,且不等待任何共享資源,則會發生這種情況。所以,他們的平均速度將是每分鍾3顆椰子(即每顆椰子平均20秒)。

內存資源共享的影響
用新的椰子錘實現了每分鍾收獲3顆椰子後,Jim和Fred第二天開始工作時看到了可怕的一幕。因為昨晚的一場大雨阻塞了半邊道路,從拖拉機到椰子樹的道路今天只能由一個人通行。所以,他們再次制訂計劃⋯⋯現在,他們有2個線程,每個線程都需要一個不能共享的資源。Th1(30秒—表示為30s)只能由一人執行,而Th2(10s)也只能由一人執行。怎麼辦?

考慮多種選擇後,他們意識到其速度的限制因素是Th1,他們能達到的最好目標是30秒收獲1顆椰子。當可以同時執行Th1(共享內存訪問)時,每個人可以順序地執行10+30s,並且兩個人都可以持續運行而無須訪問共享資源。但是現在沒有辦法對這些線程進行排序。他們能夠期望的最好結果是執行10+30s並等待20s,因為在此期間兩人都需要訪問內存。他們的速度回到平均每分鍾2顆椰子,如圖1-2 e所示。

這場大雨使他們的速度降低到每分鍾2顆椰子。Th2不再重要,因為一個人可以不慌不忙地敲椰子,而另一個人正在去摘取椰子的路上。Fred提出了這樣一個想法:他們應該從農舍再拿一把(較慢)椰子錘來幫忙。然而,這對於此時的情況絕對沒有幫助,因為收獲速度的限制因素是Th1。這種來自於某個資源的限制因素被稱為資源競爭。這個例子展示了當訪問內存是我們程序執行速度的限制因素時會發生什麼。處理數據的速度有多快(即核心運行速度)已無關緊要。我們將受到數據獲取速度的限制。即使Fred有一把可以在1秒鍾內敲碎椰子的椰子錘,但如果存在內存訪問競爭,他們仍然會被限制為每分鍾2顆椰子。在本書中,我們將區分兩種不同類型的程序:核心密集型,該類型不大依賴於內存訪問速度;存儲密集型,該類型對內存訪問速度高度敏感,正如我剛才提到的那樣。

第一個串列程序
我們已經理解了椰子世界中的並行編程,現在是時候將這些知識應用於真實計算機編程了。我會先介紹一個串列(即單線程)程序,然後將其並行化。我們的第一個串列程序imf?lip.c讀入圖1-3(左)中的小狗圖片並將其水平(中)或垂直(右)翻轉。為了簡化程序的解釋,我們將使用Bitmap(BMP)圖像格式,並將結果也輸出為BMP格式。這是一種非常容易理解的圖像格式,可以讓我們專注於程序本身。不要擔心本章中的細節,它們很快就會被解釋清楚,目前可以只關注高層的功能。

imflip.c源文件可以在Unix提示符下編譯和執行,如下所示:

gcc imflip.c -o imflip
./imflip dogL.bmp dogh.bmp V
在命令行中用「H」指定水平翻轉圖像(圖1-3中),用「V」指定垂直翻轉(圖1-3右側)。你將看到如下所示的輸出(數字可能不同,取決於你電腦的速度):

Input BMP File name : dogL.bmp (3200×2400)
Output BMP File name : dogh.bmp (3200×2400)
Total execution time : 81.0233 ms (10.550 ns per pixel)
運行該程序的CPU速度非常快,以致我必須將原始的640×480的圖像dog.bmp擴展為3200×2400的dogL.bmp,這樣它的運行時間才能被測量出來;dogL.bmp的每個維度擴大到原來的5倍,因此比dog.bmp大25倍。統計時間時,我們必須在圖像翻轉開始和結束時記錄CPU的時鍾。

理解數據傳輸速度
從磁碟讀取圖像的過程(無論是SSD還是硬碟驅動器)應該從執行時間中扣除,這很重要。換句話說,我們從磁碟讀取圖像,並確保它位於內存中(在我們的數組中),然後只統計翻轉操作所需的時間。由於不同硬體部件的數據傳輸速度存在巨大差異,我們需要分別分析在磁碟、內存和CPU上花費的時間。

在本書將要編寫的眾多並行程序中,我們重點關注CPU執行時間和內存訪問時間,因為我們可以控制它們。磁碟訪問時間(稱為I/O時間)通常在單線程中就達到極限,因而幾乎看不到多線程編程的好處。另外,請記住,當我們開始GPU編程時,較慢的I/O速度會嚴重困擾我們,因為I/O是計算機中速度最慢的部分,並且從CPU到GPU的數據傳輸要通過I/O子系統的PCI express匯流排進行,因此我們將面臨如何將數據更快地提供給GPU的挑戰。沒有人說GPU編程很容易!為了讓你了解不同硬體部件的傳輸速度,我在下面列舉了一些:

典型的網卡(NIC)具有1 Gbps的傳輸速度(千兆比特每秒或一億比特每秒)。這些卡俗稱「千兆網卡」或「Gig網卡」。請注意,1 Gbps只是「原始數據」的數量,其中包括大量的校驗碼和其他同步信號。傳輸的實際數據量少於此數量的一半。我的目的是給讀者一個大致的概念,這個細節對我們來說並不重要。

即使連接到具有6 Gbps峰值傳輸速度的SATA3介面,典型的硬碟驅動器(HDD)也幾乎無法達到1 Gbps〜2 Gbps的傳輸速度。HDD的機械讀寫性質根本不能實現快速的數據訪問。傳輸速度甚至不是硬碟的最大問題,最大問題是定位時間。HDD的機械磁頭需要一段時間在旋轉的金屬柱面上定位需要的數據,這迫使它在磁頭到達數據所在位置前必須等待。如果數據以不規則的方式分布(即碎片式的存放),則可能需要毫秒(ms)級的時間。因此,HDD的傳輸速度可能遠遠低於它所連接的SATA3匯流排的峰值速度。

連接到USB 2.0埠的快閃記憶體磁碟的峰值傳輸速度為480 Mbps(兆比特每秒或百萬比特每秒)。但是,USB 3.0標准具有更快的5 Gbps傳輸速度。更新的USB 3.1可以達到10 Gbps左右的傳輸速率。由於快閃記憶體磁碟使用快閃記憶體構建,它不需要查找時間,只需提供地址即可直接訪問數據。

典型的固態硬碟(SSD)可以連接在SATA3介面上,達到接近4 Gbps〜5 Gbps的讀取速度。因此,實際上SSD是唯一可以達到SATA3介面峰值速度的設備,即以預期的6 Gbps峰值速率傳輸數據。

一旦數據從I/O(SDD、HDD或快閃記憶體磁碟)傳輸到CPU的內存中,傳輸速度就會大大提高。已發展到第6代的Core i7系列(i7-6xxx),更高端的Xeon CPU使用DDR2、DDR3和DDR4內存技術,內存到CPU的傳輸速度為20 GBps〜60 GBps(千兆位元組每秒)。注意這個速度是千兆位元組。一個位元組有8個比特,為與其他較慢的設備進行比較,轉換為存儲訪問速度時為160 Gbps〜480 Gbps(千兆比特每秒)。

正如我們將在第二部分及以後所看到的,GPU內部存儲器子系統的傳輸速度可以達到100 GBps〜1000 GBps。例如,新的Pascal系列GPU就具有接近後者的內部存儲傳輸速率。轉換後為8000 Gbps,比CPU內部存儲器快一個數量級,比快閃記憶體磁碟快3個數量級,比HDD快近4個數量級。

imflip.c中的main( )函數
代碼1.1中所示的程序會讀取一些命令行參數,並按照命令行參數垂直或水平地翻轉輸入圖像。命令行參數由C放入argv數組中。

clock( )函數以毫秒為單位統計時間。重復執行奇數次(例如129次)操作可以提高時間統計的准確性,操作重復次數在"#define REPS 129"行中指定。該數字可以根據你的系統更改。

ReadBMP( )函數從磁碟讀取源圖像,WriteBMP( )將處理後的(即翻轉的)圖像寫回磁碟。從磁碟讀取圖像和將圖像寫入磁碟的時間定義為I/O時間,我們從處理時間中去除它們。這就是為什麼我在實際的圖像翻轉代碼之間添加"start = clock( )"和"stop = c1ock( )"行,這些代碼對已在內存中的圖像進行翻轉操作,因此有意地排除了I/O時間。

在輸出所用時間之前,imf?lip.c程序會使用一些free( )函數釋放所有由ReadBMP( )分配的內存以避免內存泄漏。

代碼1.1:imflip.c的main( ){⋯}

imflip.c中的main( )函數讀取3個命令行參數,用以確定輸入和輸出的BMP圖像文件名以及翻轉方向(水平或垂直)。該操作會重復執行多次(REPS)以提高計時的准確性。

垂直翻轉行:FlipImageV( )
代碼1.2中的FlipImageV( )遍歷每一列,並交換該列中互為垂直鏡像的兩個像素的值。有關Bitmap(BMP)圖像的函數存放在另一個名為ImageStuff.c的文件中,ImageStuff.h是對應的頭文件,我們將在下一章詳細解釋它們。圖像的每個像素都以「struct Pixel」類型存儲,包含unsigned char類型的該像素的R、G和B顏色分量。由於unsigned char佔用1個位元組,所以每個像素需要3個位元組來存儲。

ReadBMP( )函數將圖像的寬度和高度分別放在兩個變數ip.Hpixels和ip.Vpixels中。存儲一行圖像需要的位元組數在ip.Hbytes中。FlipImageV( )函數包含兩層循環:外層循環遍歷圖像的ip.Hbytes,也就是每一列,內層循環一次交換一組對應的垂直翻轉像素。

代碼1.2:imflip.c⋯FlipImageV( ){⋯}

對圖像的行做垂直翻轉,每個像素都會被讀取並替換為鏡像行中的相應像素。

水平翻轉列:FlipImageH( )
imf?lip.c的FlipImageH( )實現圖像的水平翻轉,如代碼1.3所示。除了內層循環相反,該函數與垂直翻轉的操作完全相同。每次交換使用「struct Pixel」類型的臨時像素變數pix。

由於每行像素以3個位元組存儲,即RGB、RGB、RGB⋯⋯因此訪問連續的像素需要一次讀取3個位元組。這些細節將在下一節介紹。現在我們需要知道的是,以下幾行代碼:

只是讀取位於垂直的第row行和水平的第col列處的一個像素。像素的藍色分量在地址img[row][col]處,綠色分量在地址img[row][col+1]處,紅色分量在img[row][col+2]處。在下一章中我們將看到,指向圖像起始地址的指針img由ReadBMP( )為其分配空間,然後由main( )傳遞給FlipImageH( )函數。

代碼1.3:imflip.cFlipImageH( ){⋯}

進行水平翻轉時,每個像素都將被讀取並替換為鏡像列中相應的像素。

熱點內容
卡爾頓麵包腳本策劃 發布:2025-01-21 06:34:45 瀏覽:263
界面像電腦一樣的伺服器 發布:2025-01-21 06:29:52 瀏覽:989
匿名祝福源碼 發布:2025-01-21 06:29:13 瀏覽:348
雲識別系統登陸密碼是多少 發布:2025-01-21 06:23:39 瀏覽:368
stl源碼剖析中文 發布:2025-01-21 06:14:17 瀏覽:344
我的世界手機版為什麼連不上伺服器 發布:2025-01-21 06:14:17 瀏覽:453
壓縮機的性能參數 發布:2025-01-21 06:10:34 瀏覽:607
2014年預演算法修訂歷時20年 發布:2025-01-21 06:05:46 瀏覽:191
linux切換到root用戶 發布:2025-01-21 06:05:38 瀏覽:516
php存在文件 發布:2025-01-21 06:04:51 瀏覽:171