並行和併發
並行(parallel):指在同一時刻,有多條指令在多個處理器上同時執行。
併發(concurrency):指在同一時刻只能有一條指令執行,但多個程式指令被快速的輪換執行,使得在宏觀上具有多個程式同時執行的效果,但在微觀上並不是同時執行的,只是把時間分成若干段,使多個程式快速交替的執行。
- 並行是兩個佇列同時使用兩臺咖啡機
- 併發是兩個佇列交替使用一臺咖啡機
併發:不同的執行單位,看起來是一起執行的,但是微觀上還是序列的。
並行:多核CPU同時執行。
程式 執行緒 協程
區別
- 程式是資源分配的單元,執行緒是排程的單元。
- 協程是使用者態的,只是將待執行的程式用堆疊維護起來,然後在同一個執行緒上交替執行,只是並行,不是併發。
消耗
- 多執行緒,需要CPU和核心層的上下文切換,切換的是時間片。
- 多程式,不僅是時間片,還有資源排程,更麻煩。
優勢
- 多程式的好處是資料隔離,A崩了不影響B。
- 多執行緒是共享資料的,程式間通訊會比較方便。
程式間通訊方式:管道,訊息佇列,訊號量,Socket,Streams 等。
(這些都是透過共享記憶體來通訊,而GO是利用通訊來共享記憶體。)
什麼是協程
執行緒遇到阻塞函式,只能掛起,切到別的執行緒,為了減少切換成本,java可以用非同步回撥。
非同步回撥確實不用阻塞,不過它有兩個弊端,
- 其一:割裂了原來的程式碼業務邏輯。
- 其二:陷入回撥地獄難以維護。
而Go採用了執行緒的思路:
執行緒可以在遇到阻塞的地方後,儲存執行的上下文,轉而去執行別處的程式碼。
待阻塞的請求完成後,再轉而回去繼續執行。
函式執行到一半還能中途退出再回來?
執行緒執行函式中途,遇到時間片用完或者遇到I/O阻塞,就會被作業系統儲存上下文後掛起,切換到其他執行緒。而後等到機會再回過頭繼續執行,不是嗎?
既然作業系統可以排程管理多個執行緒,那為何執行緒不可以排程管理函式的執行?
執行緒是作業系統抽象出來的執行流,由作業系統統一排程管理。
那在一個執行緒中,同樣可以抽象出多個執行流,由執行緒來統一排程管理。這執行緒之上抽象的執行流就是協程。
執行緒:
協程:
執行緒的排程由作業系統來管理,是搶佔式排程。
而協程不同,協程需要互相配合,主動交出執行權,這也是協程的名字——協作式程式的來歷。