什麼是進程和線程?
進程是應用程序的啓動實例,進程擁有代碼和打開的文件資源、數據資源、獨立的內存空間。
線程從屬於進程,是程序的實際執行者,一個進程至少包含一個主線程,也可以有更多的子線程,線程擁有自己的棧空間。
操作系統中的進程和線程
對操作系統而言,線程是最小的執行單元,進程是最小的資源管理單元。無論是進程還是線程,都是由操作系統所管理的。
線程的狀態
線程具有五種狀態:初始化、可運行、運行中、阻塞、銷燬
線程狀態的轉化關係
線程之間是如何進行協作的呢?
最經典的例子是生產者/消費者模式,即若干個生產者線程向隊列中系欸如數據,若干個消費者線程從隊列中消費數據。
生產者/消費者模式
生產者/消費者模式的性能問題是什麼?
- 涉及到同步鎖
- 涉及到線程阻塞狀態和可運行狀態之間的切換
- 設置到線程上下文的切換
什麼是協程呢?
協程(Coroutines)是一種比線程更加輕量級的存在,正如一個進程可以擁有多個線程一樣,一個線程可以擁有多個協程。
操作系統中的協程
協程不是被操作系統內核所管理的,而是完全由程序所控制,也就是在用戶態執行。這樣帶來的好處是性能大幅度的提升,因爲不會像線程切換那樣消耗資源。
協程不是進程也不是線程,而是一個特殊的函數,這個函數可以在某個地方掛起,並且可以重新在掛起處外繼續運行。所以說,協程與進程、線程相比並不是一個維度的概念。
一個進程可以包含多個線程,一個線程也可以包含多個協程。簡單來說,一個線程內可以由多個這樣的特殊函數在運行,但是有一點必須明確的是,一個線程的多個協程的運行是串行的。如果是多核CPU,多個進程或一個進程內的多個線程是可以並行運行的,但是一個線程內協程卻絕對是串行的,無論CPU有多少個核。畢竟協程雖然是一個特殊的函數,但仍然是一個函數。一個線程內可以運行多個函數,但這些函數都是串行運行的。當一個協程運行時,其它協程必須掛起。
進程、線程、協程的對比
- 協程既不是進程也不是線程,協程僅僅是一個特殊的函數,協程它進程和進程不是一個維度的。
- 一個進程可以包含多個線程,一個線程可以包含多個協程。
- 一個線程內的多個協程雖然可以切換,但是多個協程是串行執行的,只能在一個線程內運行,沒法利用CPU多核能力。
- 協程與進程一樣,切換是存在上下文切換問題的。
上下文切換
-
進程的切換者是操作系統,切換時機是根據操作系統自己的切換策略,用戶是無感知的。進程的切換內容包括頁全局目錄、內核棧、硬件上下文,切換內容保存在內存中。進程切換過程是由“用戶態到內核態到用戶態”的方式,切換效率低。
-
線程的切換者是操作系統,切換時機是根據操作系統自己的切換策略,用戶無感知。線程的切換內容包括內核棧和硬件上下文。線程切換內容保存在內核棧中。線程切換過程是由“用戶態到內核態到用戶態”, 切換效率中等。
-
協程的切換者是用戶(編程者或應用程序),切換時機是用戶自己的程序所決定的。協程的切換內容是硬件上下文,切換內存保存在用戶自己的變量(用戶棧或堆)中。協程的切換過程只有用戶態,即沒有陷入內核態,因此切換效率高。
協程的開銷爲什麼遠遠小於線程的開銷呢?