Go 協程與併發機制(一)進程與線程

【概念】

      進程和線程都是操作系統所要管理的對象。

      線程是操作系統能夠進行運算調度的最小單位。大部分情況下,它被包含在進程之中,作爲進程的實際運作單位。而進程是程序運行的實例。

【圖示】

Fig.1 進程內部結構

       在多線程程序中,一個單獨進程會有少到幾個,多到上百個線程協同工作;每個線程擁有屬於他們自己的程序計數器(指向當前指令的內存),棧,以及 TLS(線程本地內存 / 寄存器),但會共享在一個進程裏的代碼,數據以及文件。

 Fig.2 線程內部結構

      那爲什麼程序通常不採用多進程,而採取多線程的方式進行設計呢?

      進程和進程之間是不能共享內存的,線程之間可以,進程具有獨立的內存空間,這使得多進程之間的共享數據更加困難;多線程能夠更好的利用多核 CPU 的特性達到更好併發處理數據的特點;而且開啓一個新進程的開銷要比開啓一個新線程大得多。

【說明】

      ● 關於多線程在 CPU 上的處理

      操作系統調度到 CPU 中執行的最小單位是線程,在傳統單核 CPU 上運行的多線程應用程序必須交織線程,交替搶佔 CPU 的時間片,實現程序的併發執行;但是現代計算機系統普遍擁有多核處理器,在多核 CPU 上,線程可以分佈在多個 CPU 核心上,從而實現真正的並行處理。

Fig.3 單核處理器與多核處理器的區別

  ● 線程上下文切換

      在多線程模型中,一般會有用戶態線程和內核態線程這兩種狀態線程來管理我們的系統。

      用戶態線程一般是應用程序創建在用戶態支持應用的運行;內核態線程在操作系統內核態通過 IO 阻塞支持多個任務的同步調用。

      在實際生產中,程序的數量以及實際運行的線程數量會比 CPU 核心數多很多,所以爲了平衡每個線程能夠被 CPU 處理的時間並最大化利用 CPU 資源,操作系統會在適當的時間通過定時器中斷、IO 設備中斷、系統調用執行上下文切換。

      當線程發生上下文切換時,需要從操作系統用戶態轉移到內核態,記錄上一個線程的重要寄存器值,進程狀態等信息,這些信息存儲在操作系統線程控制塊中。

      當切換到下一個要執行的線程時,需要加載重要的 CPU 寄存器值,並從內核態轉移到操作系統用戶態。如果線程在上下文切換時屬於不同的進程,那麼需要更新額外的狀態信息及內存地址空間,同時將新的頁表導入內存。

  ● 併發與並行

      在程序設計中,有兩個很容易被誤解的概念就是併發 (concurrency) 和並行 (parallelism),通俗來講,併發是指同時處理多個任務的能力,這些任務是獨立的執行單元。

      與並行相區別的是,併發並不意味着同一時刻所有任務都在執行,而是在一個時間段內,所有任務都能通過線程上下文切換交替執行的方式執行完畢,開發者並不關心在某一時刻具體執行的是哪個任務。

      多核處理器是真正的並行執行,因爲在任意時刻,可以同時有多個線程在執行。

      在實際的多核處理場景中,併發和並行常常是同時存在的,即多核在並行處理多個線程,而單核中的多個線程又在上下文切換中交替執行。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/nqFE-cFaZ4rl4Yqi32Gwng