)
簡介這份資源是天津大學(xué)并行計算課程的配套學(xué)習(xí)資料面向計算機專業(yè)學(xué)生、高性能計算方向的學(xué)習(xí)者以及需要系統(tǒng)梳理并行編程知識的技術(shù)人員幫助其理解共享內(nèi)存與分布式內(nèi)存模型、掌握OpenMP與MPI等并行編程工具并具備將串行算法改造為并行程序的能力。壓縮包為zip格式整體約44.18MB文件總數(shù)與類型明細(xì)上游暫未提供從內(nèi)容看應(yīng)包含課程講義、實驗報告與復(fù)習(xí)總結(jié)等材料。目前已有1587人學(xué)習(xí)具備一定的參考價值。資料圍繞并行計算基礎(chǔ)、負(fù)載均衡、同步與互斥、分治與歸約掃描等并行算法設(shè)計策略展開并結(jié)合Amdahl定律與Gustafson定律進行性能分析實驗部分涉及并行排序、矩陣運算、圖形渲染等場景復(fù)習(xí)總結(jié)則梳理考試重點與解題思路便于讀者對照實驗代碼鞏固理論、查漏補缺。1. 并行計算到底在算什么從“一個人搬磚”到“一群人搬磚”的直覺你第一次聽到“并行計算”這四個字大概率是在某門課、某個項目介紹或者一份資料標(biāo)題里。它聽起來很唬人像是只有超級計算機才配談的東西。但說白了它解決的是一個特別樸素的問題活兒太多一個人干不完怎么辦打個比方。你要把一萬塊磚從樓下搬到樓上。一個人搬來回一萬趟累死也得好幾天。但如果你叫來十個人每人搬一千塊時間立刻縮到十分之一。并行計算干的就是這件事——只不過搬的不是磚是計算任務(wù)叫來的不是人是 CPU 核心、GPU 線程或者一整個計算集群。它的核心思想就一句話把一個大任務(wù)拆成許多能同時干的小任務(wù)讓多個計算單元一起動手從而縮短總時間。為什么值得搞懂因為今天你用的手機、電腦、服務(wù)器幾乎全是多核的。單核性能早就撞上了物理天花板廠商拼的是“核多不多、能不能協(xié)同”。不懂并行你寫出來的程序可能只用到一個核剩下七個核在旁邊看戲——這就是很多“玄學(xué)卡頓”的根源。并行計算不是什么高冷概念它是理解現(xiàn)代硬件如何真正干活的一把鑰匙。2. 為什么非要并行單核撞墻之后算力只能靠“人多”2.1 頻率上不去了核數(shù)成了新賽道早年間提升算力很簡單把 CPU 主頻往上拉就行。但從十幾年前開始這條路走不動了。主頻越高發(fā)熱和功耗越夸張散熱壓不住芯片也扛不住。工程師們換了個思路既然單個核心快不了那就多放幾個核心讓它們同時干活。于是雙核、四核、八核乃至幾十核的處理器成了常態(tài)。這帶來一個直接后果硬件已經(jīng)把“人多”的條件給你了但軟件得跟得上。一個只按“一個人搬磚”思路寫的程序放到八核機器上依然只有一個核在忙。并行計算就是教你怎么把任務(wù)分出去讓多出來的核真正派上用場。換句話說并行不是可選項而是榨干現(xiàn)代硬件性能的必經(jīng)之路。2.2 兩種“人多”的方式多進程與多線程讓多個計算單元同時干活常見的有兩條路。一條叫多進程每個進程是獨立的“工人”各有各的內(nèi)存空間互不干擾適合把大任務(wù)切成幾塊互不依賴的子任務(wù)。另一條叫多線程多個線程共享同一塊內(nèi)存像同一個車間里的幾個工人共用一張工作臺溝通方便但也容易互相踩腳。用 Python 寫個最直觀的對比感受一下“串行”和“并行”的差別import time from multiprocessing import Pool def heavy_task(n): # 模擬一段耗時的計算比如累加 total 0 for i in range(n): total i * i return total if __name__ __main__: tasks [10_000_000] * 4 # 四個相同的重任務(wù) # 串行一個接一個地算 start time.time() serial_result [heavy_task(t) for t in tasks] print(串行耗時:, time.time() - start) # 并行開四個進程同時算 start time.time() with Pool(processes4) as pool: parallel_result pool.map(heavy_task, tasks) print(并行耗時:, time.time() - start)這段代碼里Pool(processes4)就是叫來四個“工人”pool.map把四個任務(wù)分給它們同時干。參數(shù)processes控制工人數(shù)量一般設(shè)成 CPU 核心數(shù)比較合適。跑下來你會發(fā)現(xiàn)并行耗時明顯更短——這就是并行的直接收益。當(dāng)然真實場景遠比這復(fù)雜任務(wù)之間可能有依賴、要共享數(shù)據(jù)那就得換更精細(xì)的拆分方式。2.3 并行的收益不是白來的阿姆達爾定律的提醒并行不是萬能加速藥。有個很實在的規(guī)律叫阿姆達爾定律一個程序里能并行的部分越多加速比才越高如果有一大段必須串行執(zhí)行那不管你加多少核總時間也降不下去。打個比方十個人搬磚很快但如果只有一把鑰匙、必須排隊開門那開門這段時間誰也幫不上忙。這提醒我們做并行優(yōu)化先找“串行瓶頸”在哪。很多時候程序慢不是核不夠而是某一段邏輯天生只能一個人干。盲目加線程、加進程可能只是讓更多工人在門口排隊反而增加調(diào)度開銷。理解這一點你就不會把并行當(dāng)成“無腦加速開關(guān)”而是帶著判斷去用它。3. 并行計算和它的“親戚們”別把并發(fā)、分布式、向量化混成一鍋3.1 并行與并發(fā)一個在“同時干”一個在“輪流干”這是初學(xué)者最容易混的一對詞。并行強調(diào)的是同一時刻真的有多個任務(wù)在同時推進比如四核同時算四份數(shù)據(jù)。并發(fā)強調(diào)的是“看起來同時在處理多件事”但底層可能只有一個核靠快速切換輪流干就像一個人同時接三個電話其實是來回切換。為什么容易混因為日常口語里這倆詞幾乎不分。怎么區(qū)分看硬件并行需要多個物理計算單元真正同時工作并發(fā)是一種任務(wù)組織方式單核也能并發(fā)。寫程序時并發(fā)關(guān)心的是“怎么把任務(wù)調(diào)度得井井有條”并行關(guān)心的是“怎么讓多個單元同時出力”。兩者常常一起用但概念不能劃等號。3.2 并行與分布式一個在“一間屋”一個在“幾棟樓”并行計算通常指同一臺機器內(nèi)的多個核心協(xié)同共享內(nèi)存、通信極快。分布式計算則是把任務(wù)分散到多臺機器上機器之間靠網(wǎng)絡(luò)通信延遲高、還可能斷線。打個比方并行是同一個車間里的工人協(xié)作喊一嗓子就聽見分布式是幾個城市的分廠協(xié)同得靠電話和物流。為什么混因為兩者目標(biāo)都是“多算力一起干活”。區(qū)分的關(guān)鍵在通信成本和故障模型并行里內(nèi)存訪問是納秒級分布式里網(wǎng)絡(luò)往返是毫秒級甚至更久而且分布式還得考慮某臺機器掛了怎么辦。所以同一套拆分思路落到分布式上要額外處理數(shù)據(jù)一致性和容錯不能照搬。3.3 并行與向量化一個靠“人多”一個靠“手快”向量化是指讓一條指令同時處理多個數(shù)據(jù)比如 SIMD 技術(shù)一個操作搞定一組數(shù)。它不增加“工人數(shù)量”而是讓每個工人一次搬多塊磚。并行則是增加工人。兩者可以疊加多個核心各自再做向量化性能還能再上一層。容易混是因為都叫“加速”。區(qū)分看粒度向量化是指令級的細(xì)粒度并行通常由編譯器或特定寫法觸發(fā)并行是任務(wù)級或線程級的粗粒度拆分需要你主動設(shè)計任務(wù)怎么分。搞不清這點你可能以為寫了循環(huán)就自動并行了其實編譯器只是幫你做了向量化核還是只用了一個。3.4 常見誤區(qū)核越多越快、線程越多越好最后一個高頻誤區(qū)以為加核、加線程就一定更快。實際上線程太多會帶來上下文切換開銷進程太多會爭搶內(nèi)存帶寬任務(wù)拆得太碎則調(diào)度成本超過計算本身。就像搬磚叫來一百個人樓梯口擠成一團反而誰都動不了。怎么避開先測量再優(yōu)化用工具看程序到底卡在哪是計算密集還是等待密集串行部分占多少。然后小步試線程數(shù)從核心數(shù)起步觀察耗時變化找到拐點。記住并行是手段不是目的目標(biāo)是總時間更短而不是數(shù)字上“看起來更熱鬧”。4. 什么時候該上并行什么時候別硬上一份判斷清單4.1 適合并行的場景長什么樣判斷一個任務(wù)該不該并行先看它能不能被“切開”。如果任務(wù)能自然拆成許多互不依賴的小塊比如對一大批圖片做同樣的濾鏡處理、對海量數(shù)據(jù)做獨立統(tǒng)計、矩陣乘法里各元素的計算那并行就是天作之合。這類任務(wù)有個共同點每塊的計算量足夠大大到調(diào)度開銷可以忽略。再看數(shù)據(jù)規(guī)模。數(shù)據(jù)量小的時候串行幾毫秒就跑完了你花力氣拆任務(wù)、開進程光啟動開銷就比計算還長純屬折騰。數(shù)據(jù)量大、單次計算重并行的收益才明顯。還有一個信號程序跑起來時你打開任務(wù)管理器發(fā)現(xiàn)只有一個核在滿負(fù)荷其余在摸魚——這就是典型的“該并行卻沒并行”。4.2 不適合硬上的情況有些任務(wù)天生串行。比如每一步都依賴上一步結(jié)果的計算像遞推、某些圖算法你沒法讓第二步和第一步同時跑。還有些任務(wù)共享狀態(tài)極多加鎖、同步的成本高到把并行收益吃光這時候硬上并行程序不但不快還可能因為死鎖、競態(tài)條件翻車調(diào)試起來全是血淚經(jīng)驗。另外I/O 密集型的任務(wù)要分清如果瓶頸在讀寫磁盤或網(wǎng)絡(luò)等待那多開線程可能有用讓等待重疊但這更接近并發(fā)調(diào)度而非純計算并行。別把“等得久”誤當(dāng)成“算得慢”方向錯了加多少核都白搭。判斷維度適合并行不適合硬上任務(wù)依賴子任務(wù)相互獨立強前后依賴、必須串行數(shù)據(jù)規(guī)模數(shù)據(jù)量大、單次計算重數(shù)據(jù)極小、秒級完成共享狀態(tài)少量或可分區(qū)大量共享、頻繁加鎖瓶頸類型計算密集I/O 等待為主或串行段過長4.3 一個具體例子圖像批處理的取舍假設(shè)某圖像處理 Demo 要對上萬張圖片做同一種降噪處理。每張圖互不相關(guān)單張?zhí)幚砗臅r幾十毫秒這就是典型的可并行任務(wù)。做法是把圖片列表切成若干份開多個進程各處理一份進程數(shù)設(shè)成核心數(shù)附近觀察耗時找最優(yōu)值。這里的關(guān)鍵不是代碼多復(fù)雜而是“切得合理”切太細(xì)進程調(diào)度開銷上來切太粗負(fù)載不均有的核早早干完在等。反過來如果這個 Demo 里還有一步是“把所有圖片按處理結(jié)果排序后再統(tǒng)一輸出”那排序和匯總這段就是串行瓶頸并行只能加速前面的處理段。這時候更聰明的做法是先把能并行的部分榨干再評估串行段是否值得優(yōu)化而不是一味堆進程。從那以后我每次動手做并行之前都會先問自己三個問題任務(wù)能不能切、切完收益夠不夠大、串行瓶頸在哪。想清楚再寫比寫完發(fā)現(xiàn)只快了一點點要省心得多。希望這份梳理能幫你在遇到“并行計算”這個詞時不再一頭霧水而是能一眼看出它適不適合眼前這攤活兒。本文還有配套的精品資源點擊獲取