-
併發/並行
從物理基礎元素角度來看,當只有一個CPU時,執行一個程序這個程序就會一直佔用CPU,直到程序運行結束。
如果這個程序的運行過程中,需要用到CPU的部分很快就結束了,程序的其他環節(比如IO阻塞等)正在佔用時間,此時CPU是空置的。
於是就有了併發。
-
併發的不足
併發執行加速了對CPU的使用效率,也帶來了問題。
程序A運行到一半,程序B進來搶佔CPU,程序A的中間狀態/內存/變量怎麼辦?
因此,在同一個CPU裏的併發需要處理好上下文切換的問題。
-
進程的出現
讓CPU處理兩個程序,就像男女結婚一樣。兩人結婚並不是兩個人湊在一起過日子,而是兩個家庭在進程資產重組。不是丈夫+妻子,而是丈夫+妻子and丈夫+岳父and丈夫+岳母and妻子+婆婆…
將計算主業及所需附屬等整合在一起抽象出來的概念,就叫進程。
這個概念能夠獨立運行。涉及到大量計算機資源的配置,如果任由用戶程序配置,太過複雜也會衝突。
因此就出現了操作系統。
操作系統直接跟底層資源配置打交道,用戶程序只需要跟操作系統打交道就行了。
-
上下文切換(Context Switch)
上下文切換主要是指進程的上下文切換,發生在內核態,由內核調度器執行。
上下文,指的是進程的運行狀態。
當一個進程的時間片用完,內核將保存該進程的運行狀態(即上下文),將其存入運行隊列(Run Queue),同時讓新的進程佔用CPU。
進程的上下文包括:
- 內存地址空間
- 內核態堆棧
- 硬件上下文(CPU寄存器)
開銷較大。
爲了降低開銷,出現了線程。
-
線程的出現
通過進程切換,充分利用CPU,然而進程切換過程中上下文切換是個高開銷事件,就像兩家人用共享同一棟房子,今天你拖家帶口搬進去,明天他家鍋碗瓢盆再搬一通,這個中間過程太費勁。
現在兩家人各站一半房間,只對廚房進行輪換使用,這樣開銷小了,就是說上下文的包含範圍減小了。
大量進程之間的切換過程會消耗很多系統資源,爲了降低資源消耗,就出現了線程。
同一個進程中可以有不同的線程,這些線程可以共享一個地址空間、頁表緩存區,每個線程只需要維護自己的寄存器、棧、相關變量。
最初是沒有操作系統的,因爲人工配置每個進程、線程的資源工程複雜又容易造成計算機崩潰,纔有了操作系統(內核),操作系統嫁接在計算機硬件和程序代碼之間,上面談到的進程/線程切換,都是下沉到內核中由內核操作的,稱爲內核態。
爲了進一步降低內核態線程上下文切換的開銷,纖程出現了。
-
纖程(Fiber)
纖程(Fiber)是一種最輕量化的線程(lightweight threads)。它是一種用戶態線程(user thread),讓應用程序可以獨立決定自己的線程要如何運作。操作系統內核不能看見它,也不會爲它進行調度。
就像一般的線程,纖程有自己的定址空間。但是纖程採取合作式多任務(Cooperative multitasking),而線程採取先佔式多任務(Pre-emptive multitasking)。應用程序可以在一個線程環境中創建多個纖程,然後手動運行它。纖程不會被自動運行,必須要由應用程序自己指定讓它運行,或換到下一個纖程。
跟線程相比,纖程較不需要操作系統的支持。
一個線程內可以創建成千上萬個纖程。
纖程用於化異步爲同步 ,沒有了線程所謂的安全問題, 避免鎖機制。
簡單理解:爲了進一步減小內核態線程上下文切換的開銷,於是有了用戶態線程設計,即纖程。
-
用戶態線程
如果連時鐘阻塞、 線程切換這些功能我們都不需要了,自己在進程裏面寫一個邏輯流調度的東西。那麼我們即可以利用到併發優勢,又可以避免反覆系統調用,還有進程切換造成的開銷,分分鐘給你上幾千個邏輯流不費力。這就是用戶態線程。
-
終於出現協程
如果一種實現使得每個線程需要自己通過調用某個方法,主動交出控制權。那麼我們就稱這種用戶態線程是協作式的,即是協程。
協程的做法很像早期操作系統的協作式多任務。
協作式多任務:當任務得一個到了 CPU 時間,除非它自己放棄使用 CPU ,否則將完全霸佔 CPU。
協程(coroutine)顧名思義就是“協作的例程”(co-operative routines)。跟具有操作系統概念的線程不一樣,協程是在用戶空間利用程序語言的語法語義就能實現邏輯上類似多任務的編程技巧。
協程的核心思想在於:控制流的主動讓出和恢復。
這一點和上文說的用戶態線程有幾分相似,但是用戶態線程多在語言層面實現,對於使用者還是不夠開放,無法提供顯示的調度方式。但是協程做到了這一點,用戶可以在編碼階段通過類似
yieldto
原語對控制流進行調度。 -
References
單核CPU、並行、進程、線程、纖程、協程出現必要性解析
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.