進程,線程和協程

1,任務調度

要理解進程和線程,必需要先了解一下操做系統的一些相關概念。大部分操做系統(如Windows、Linux)的任務調度是採用時間片輪轉的搶佔式調度方式,也就是說一個任務執行一小段時間後強制暫停去執行下一個任務,每一個任務輪流執行。任務執行的一小段時間叫作時間片,任務正在執行時的狀態叫運行狀態,任務執行一段時間後強制暫停去執行下一個任務,被暫停的任務就處於就緒狀態等待下一個屬於它的時間片的到來。這樣每一個任務都能獲得執行,因爲CPU的執行效率很是高,時間片很是短,在各個任務之間快速地切換,給人的感受就是多個任務在「同時進行」,這也就是咱們所說的併發(別以爲併發有多高深,它的實現很複雜,但它的概念很簡單,就是一句話:多個任務同時執行)。多任務運行過程的示意圖以下:
 程序員

操做系統中的任務調度數據庫

2,進程

咱們都知道計算機的核心是CPU,它承擔了全部的計算任務;而操做系統是計算機的管理者,它負責任務的調度、資源的分配和管理,統領整個計算機硬件;應用程序側是具備某種功能的程序,程序是運行於操做系統之上的。多線程

進程是一個具備必定獨立功能的程序在一個數據集上的一次動態執行的過程,是應用程序運行的載體,操做系統會以進程爲單位,分配系統資源(CPU時間片、內存等資源),進程是資源分配的最小單位進程通常由程序、數據集合和進程控制塊三部分組成。併發

  • 程序用於描述進程要完成的功能,是控制進程執行的指令集;
  • 數據集合是程序在執行時所須要的數據和工做區;
  • 程序控制塊(Program Control Block,簡稱PCB),包含進程的描述信息和控制信息,是進程存在的惟一標誌。

進程具備的特徵:異步

  • 動態性:進程是程序的一次執行過程,是臨時的,有生命期的,是動態產生,動態消亡的;
  • 併發性:任何進程均可以同其餘進程一塊兒併發執行;
  • 獨立性:進程是系統進行資源分配和調度的一個獨立單位;
  • 結構性:進程由程序、數據和進程控制塊三部分組成。

【進程間通訊(IPC)】性能

  • 管道(Pipe)、命名管道(FIFO)、消息隊列(Message Queue) 、信號量(Semaphore) 、共享內存(Shared Memory);套接字(Socket)。

3,線程

早期的操做系統中並無線程的概念,進程是能擁有資源和獨立運行的最小單位,也是程序執行的最小單位。任務調度採用的是時間片輪轉的搶佔式調度方式,而進程是任務調度的最小單位,每一個進程有各自獨立的一塊內存,使得各個進程之間內存地址相互隔離。至關於一個進程裏只有一個線程,進程自己就是線程。因此線程有時被稱爲輕量級進程(Lightweight Process,LWP)spa

​​

早期的操做系統只有進程,沒有線程操作系統

 

後來,隨着計算機的發展,對CPU的要求愈來愈高,進程之間的切換開銷較大,已經沒法知足愈來愈複雜的程序的要求了。因而就抽象出一個更小的概念——線程線程是程序執行中一個單一的順序控制流程,是程序執行流的最小單元,是處理器調度和分派的基本單位。線程

一個進程能夠有一個或多個線程,各個線程之間共享程序的內存空間 (也就是所在進程的內存空間) 。3d

一個標準的線程由線程ID、當前指令指針(PC)、寄存器和堆棧組成。而進程由內存空間(代碼、數據、進程空間、打開的文件)和一個或多個線程組成。

線程的出現,使得一個進程能夠有多個線程

單線程與多線程的關係

 

用戶線程和內核線程的關係模型

線程又被稱爲 用戶線程(用戶態),每個用戶線程都要有一個 內核線程(內核態) 在支持。用戶線程 與 內核線程的對應關係有三種模型:一對一模型、多對一模型、多對多模型,在這以4個內核線程、3個用戶線程爲例對三種模型進行說明:

一對一模型

對於一對一模型來講,一個用戶線程就惟一地對應一個內核線程(反過來不必定成立,一個內核線程不必定有對應的用戶線程)。這樣,若是CPU沒有采用超線程技術(如四核四線程的計算機),一個用戶線程就惟一地映射到一個物理CPU的線程,線程之間的併發是真正的併發。一對一模型使用戶線程具備與內核線程同樣的優勢,一個線程因某種緣由阻塞時其餘線程的執行不受影響;此處,一對一模型也可讓多線程程序在多處理器的系統上有更好的表現。

但一對一模型也有兩個缺點:1. 許多操做系統限制了內核線程的數量,所以一對一模型會使用戶線程的數量受到限制;2. 許多操做系統內核線程調度時,上下文切換的開銷較大,致使用戶線程的執行效率降低。

一對一模型

多對一模型

多對一模型將多個用戶線程映射到一個內核線程上,線程之間的切換由用戶態的代碼來進行,所以相對一對一模型,多對一模型的線程切換速度要快許多;此外,多對一模型對用戶線程的數量幾乎無限制。但多對一模型也有兩個缺點:1. 若是其中一個用戶線程阻塞,那麼其它全部線程都將沒法執行,由於此時內核線程也隨之阻塞了;2. 在多處理器系統上,處理器數量的增長對多對一模型的線程性能不會有明顯的增長,由於全部的用戶線程都映射到一個處理器上了。

多對一模型

多對多模型

多對多模型結合了一對一模型和多對一模型的優勢,將多個用戶線程映射到多個內核線程上。多對多模型的優勢有:1. 一個用戶線程的阻塞不會致使全部線程的阻塞,由於此時還有別的內核線程被調度來執行;2. 多對多模型對用戶線程的數量沒有限制;3. 在多處理器的操做系統中,多對多模型的線程也能獲得必定的性能提高,但提高的幅度不如一對一模型的高。在如今流行的操做系統中,大都採用多對多的模型。

多對多模型

4,進程與線程的區別

前面講了進程與線程,但可能你還以爲迷糊,感受他們很相似。的確,進程與線程有着千絲萬縷的關係,下面就讓咱們一塊兒來理一理:

4.1 進程是操做系統分配資源的最小單位,線程是程序執行的最小單位;

4.2 一個進程由一個或多個線程組成,線程是一個進程中代碼的不一樣執行路線;

4.3 進程之間相互獨立,但同一進程下的各個線程之間共享程序的內存空間(包括代碼段、數據集、堆等)及一些進程級的資源(如打開文件和信號),某進程內的線程在其它進程不可見;

4.4 調度和切換:線程上下文切換比進程上下文切換要快得多。

進程與線程的資源共享關係

 

5,協程

協程,英文Coroutines,是一種基於線程,但又比線程更加輕量級的存在,這種由程序員本身寫程序來管理的輕量級線程叫作『用戶空間線程』,具備對內核來講不可見的特性。

由於是自主開闢的異步任務,因此不少人也更喜歡叫它們纖程(Fiber),或者綠色線程(GreenThread)。正如一個進程能夠擁有多個線程同樣,一個線程也能夠擁有多個協程。

5.1 協程的目的

在傳統的J2EE系統中都是基於每一個請求佔用一個線程去完成完整的業務邏輯(包括事務)。因此係統的吞吐能力取決於每一個線程的操做耗時。若是遇到很耗時的I/O行爲,則整個系統的吞吐馬上降低,由於這個時候線程一直處於阻塞狀態,若是線程不少的時候,會存在不少其餘的線程處於等待,空閒狀態(等待前面的線程執行完才能執行),形成了資源應用不完全。

最多見的例子就是JDBC(它是同步阻塞的),這也是爲何不少人都說數據庫是瓶頸的緣由。這裏的耗時實際上是讓CPU一直在等待I/O返回,說白了線程根本沒有利用CPU去作運算,而是處於空轉狀態。而另外過多的線程,也會帶來更多的ContextSwitch(上下文切換)開銷。

而協程的目的就是當出現長時間的I/O操做時,經過讓出(yield)目前的協程調度,執行下一個任務的方式,來消除ContextSwitch上的開銷。

5.2 協程的特色

  1. 線程的切換由操做系統負責調度,協程由用戶本身進行調度,所以減小了上下文切換,提升了效率
  2. 線程的默認Stack大小是1M,而協程更輕量,接近1K。所以能夠在相同的內存中開啓更多的協程。
  3. 因爲在同一個線程上,所以能夠避免競爭關係而使用鎖
  4. 適用於被阻塞的,且須要大量併發的場景。但不適用於大量計算的多線程,遇到此種狀況,更好實用線程去解決。

5.3 協程的原理

當出現IO阻塞的時候,由協程的調度器進行調度,經過將數據流馬上yield掉(主動讓出),而且記錄當前棧上的數據,阻塞完後馬上再經過線程恢復棧,並把阻塞的結果放到這個線程上去跑,這樣看上去好像跟寫同步代碼沒有任何差異,這整個流程能夠稱爲coroutine,而跑在由coroutine負責調度的線程稱爲Fiber。好比Golang裏的 go關鍵字其實就是負責開啓一個Fiber,讓func邏輯跑在上面。

因爲協程的暫停徹底由程序控制,發生在用戶態上;而線程的阻塞狀態是由操做系統內核來進行切換,發生在內核態上。
所以,協程的開銷遠遠小於線程的開銷,也就沒有了ContextSwitch上的開銷。

 

5.4 總結和比較

比較項 進程 線程 協程
佔用資源 隨程序運行所需內存而變化 初始單位爲1MB,固定不可變 初始通常爲 2KB,可隨須要而增大
調度所屬 資源分配由OS完成 由 OS 的內核完成 由用戶完成
切換開銷 進程切換開銷很大 涉及模式切換(從用戶態切換到內核態)、16個寄存器、PC、SP...等寄存器的刷新等 只有三個寄存器的值修改 - PC / SP / DX.
性能問題 進程獨立運行 穩健

資源佔用過高,頻繁建立銷燬會帶來嚴重的性能問題,
線程之間上下文切換帶來性能問題

資源佔用小,不會帶來嚴重的性能問題,
在線程內部切換
數據同步 可經過進程間通訊進行數據交換 須要用鎖等機制確保數據的一直性和可見性 不須要多線程的鎖機制,由於只有一個線程,也不存在同時寫變量衝突,在協程中控制共享資源不加鎖,只須要判斷狀態就行了,因此執行效率比多線程高不少。

進程:是系統調度和分配資源的最小單位,擁有本身獨立的堆和棧,進程由操做系統調度進程。進程維護的是程序所包含的資源(靜態資源), 如:地址空間,打開的文件句柄集,文件系統狀態,信號處理handler等
線程:是CPU調度和分配任務的最小單位,擁有本身獨立的棧,與同一個進程下的其餘線程共享所屬進程的堆,標準線程由操做系統調度。線程維護的運行相關的資源(動態資源),如:運行棧,調度相關的控制信息,待處理的信號集等
協程:擁有本身獨立的棧,與同一個進程下的其餘線程共享所屬進程的堆,協程由程序員在協程的代碼裏顯式調度;

參考連接:https://www.jianshu.com/p/80bde972196d

相關文章
相關標籤/搜索