併發程式設計概覽

快樂的提千萬發表於2023-02-12

並行和併發

並行(parallel):指在同一時刻,有多條指令在多個處理器上同時執行。

併發(concurrency):指在同一時刻只能有一條指令執行,但多個程式指令被快速的輪換執行,使得在宏觀上具有多個程式同時執行的效果,但在微觀上並不是同時執行的,只是把時間分成若干段,使多個程式快速交替的執行。

  • 並行是兩個佇列同時使用兩臺咖啡機
  • 併發是兩個佇列交替使用一臺咖啡機

併發:不同的執行單位,看起來是一起執行的,但是微觀上還是序列的。

並行:多核CPU同時執行。

程式 執行緒 協程

區別

  • 程式是資源分配的單元,執行緒是排程的單元。
  • 協程是使用者態的,只是將待執行的程式用堆疊維護起來,然後在同一個執行緒上交替執行,只是並行,不是併發。

消耗

  • 多執行緒,需要CPU和核心層的上下文切換,切換的是時間片。
  • 多程式,不僅是時間片,還有資源排程,更麻煩。

優勢

  • 多程式的好處是資料隔離,A崩了不影響B。
  • 多執行緒是共享資料的,程式間通訊會比較方便。

程式間通訊方式:管道,訊息佇列,訊號量,Socket,Streams 等。

(這些都是透過共享記憶體來通訊,而GO是利用通訊來共享記憶體。)

什麼是協程

執行緒遇到阻塞函式,只能掛起,切到別的執行緒,為了減少切換成本,java可以用非同步回撥。

非同步回撥確實不用阻塞,不過它有兩個弊端,

  • 其一:割裂了原來的程式碼業務邏輯。
  • 其二:陷入回撥地獄難以維護。

而Go採用了執行緒的思路:

執行緒可以在遇到阻塞的地方後,儲存執行的上下文,轉而去執行別處的程式碼。

待阻塞的請求完成後,再轉而回去繼續執行。

函式執行到一半還能中途退出再回來?

執行緒執行函式中途,遇到時間片用完或者遇到I/O阻塞,就會被作業系統儲存上下文後掛起,切換到其他執行緒。而後等到機會再回過頭繼續執行,不是嗎?

既然作業系統可以排程管理多個執行緒,那為何執行緒不可以排程管理函式的執行?


執行緒是作業系統抽象出來的執行流,由作業系統統一排程管理。

那在一個執行緒中,同樣可以抽象出多個執行流,由執行緒來統一排程管理。這執行緒之上抽象的執行流就是協程。

執行緒:

協程:

執行緒的排程由作業系統來管理,是搶佔式排程。

而協程不同,協程需要互相配合,主動交出執行權,這也是協程的名字——協作式程式的來歷。

相關文章