併發還是並行
- 併發程序:含有多個邏輯上的獨立執行塊,它們可以獨立並行執行,也可以串行執行。
- 並行程序:跟串行程序相對,它比串行程序快的原因:可以同時執行整個任務的多個部分。並行程序可能有多個獨立執行塊,也可能只有一個。
從另一個角度來理解併發和並行:
- 併發:是問題域中的概念,程序需要被設計成能夠處理多個同時(或幾乎同時的)發生的事件。
- 並行:是方法域中的概念,將問題的多個部分同時執行,來加速解決問題。
引用Rob Pike
(Go語言之父)的經典論述:
- 併發:是同一時間處理(dealing with)多件事情的能力。
- 並行:是同一時間做(doing)多件事情的能力。
實際案例:
- 併發:王老師在聽同學朗讀的時候,她可以暫停同學的朗讀,然後回答其它同學的問題。(這是
併發
但是不是並行
,因爲僅有王老師一個人,某一時刻只能做一件事情) - 並行:如果王老師還有一位助教小紅,王老師聽同學朗讀,小紅回答其它同學的問題,這是併發(同時處理多件事情),也是並行(同時做多件事情)。
個人理解:
- 併發:比如一個人做晚餐,用電飯鍋開始煮飯後,開始熱鍋炒菜,鍋在預熱的時候,再去燒一壺水,這是併發,同時在處理多件事情 。
- 並行:比如兩個人做晚餐,一個人在炒菜,一個人在煲湯,或者一個人在炒青菜,另一個人在煎魚,這是並行,同時有多個人在做事情。
併發與並行易混淆的原因:
傳統的
線程與鎖
模型不支持並行。如果要用線程與鎖模型寫一個並行程序,只能寫一個併發的程序,同時運行在多核機器上。
併發:天生帶有不確定性,它會隨着事件時序的改變而給出不同的結果。
並行:可以是確定的,如將數組中的每個數都加倍,把數組分成兩部分,分別交給一個核處理,這種做法運行結果是確定的。用支持並行的語言寫出並行程序,從而排除不確定性。
並行架構
並行不等同於多核
現代計算機在不同層次上都使用了並行技術,單核機器運行速度越來越快的原因也是在於在位級和指令級上使用了並行技術。
並行架構有四個層級:
- 位級(bit-level)並行。
- 指令級(instruction-level)並行。
- 數據級(data-level)並行。
- 任務級(task-level)並行。
位級並行
爲什麼32位的計算機運行速度比8位更快?因爲並行。
兩個32位數的加法,8位計算機要進行多次8位計算,而32位計算機可以一步完成。
指令級並行
現代CPU的並行度很高,其中使用的技術包括流水線、亂序執行和猜測執行等。
流水線,亂序執行,猜測執行具體含義?待補充。
數據級並行
數據級並行也稱爲單指令多數據(SIMD)架構,可以並行地在大量數據上施加同一操作,圖形處理器(GPU)就是強大的數據並行處理器(比如,如增加圖片的亮度,就需要增加每個像素點的亮度)。
任務級並行
任務級並行最明顯的特徵是其內存模型:共享內存模型或分佈式內存模型。
共享內存模型
對於共享內存模型,每個處理器都能夠訪問整個內存,處理器之間的通信主要通過內存進行。
分佈式內存模型
對於分佈式內存模型,每個處理器都有自己的內存,處理器之間的通信主要通過網絡進行。
兩種內存模型比較
- 共享內存模型因爲通信過程相對簡單,所以用共享內存模型編程更加容易。
- 如果要開發高可用系統,規避硬件故障對系統的影響,這個時候只能選用分佈式內存模型。
併發:不只是多核
使用併發的目的,不僅僅是爲了利用多核處理器的優勢,正確使用併發,還能獲得諸如及時響應、高效、簡單、容錯性高等優點。
使用併發還有基於如下因素考慮:
- 世界是併發的,爲了與其有效交互,軟件也應是併發的。
- 爲了處理分佈式問題。
- 增強軟件的容錯性,併發代碼的關鍵是獨立性和故障檢測。獨立性是出了故障的任務不會影響到其它任務,故障檢測指的是當一個任務出現故障時,能夠通知負責處理故障的任務來執行。
- 世界是複雜多變的,使用併發程序來處理現實問題相對串行程序更簡單。