進程、線程、協程

1、進程

進程是具備必定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。每一個進程都有本身的獨立內存空間,不一樣進程經過進程間通訊來通訊。因爲進程比較重量,佔據獨立的內存,因此上下文進程間的切換開銷(棧、寄存器、虛擬內存、文件句柄等)比較大,但相對比較穩定安全。html

 

2、線程python

線程的出現是爲了下降上下文切換的消耗,提升系統的併發性,並突破一個進程只能幹同樣事的缺陷,使到進程內併發成爲可能。假設,一個文本程序,須要接受鍵盤輸入,將內容顯示在屏幕上,還須要保存信息到硬盤中。若只有一個進程,勢必形成同一時間只能幹同樣事的尷尬(當保存時,就不能經過鍵盤輸入內容)。如有多個進程,每一個進程負責一個任務,進程A負責接收鍵盤輸入的任務,進程B負責將內容顯示在屏幕上的任務,進程C負責保存內容到硬盤中的任務。這裏進程A,B,C間的協做涉及到了進程通訊問題,並且有共同都須要擁有的東西——-文本內容,不停的切換形成性能上的損失。如有一種機制,可使任務A,B,C共享資源,這樣上下文切換所須要保存和恢復的內容就少了,同時又能夠減小通訊所帶來的性能損耗,那就行了。是的,這種機制就是線程。線程也叫輕量級進程,它是一個基本的CPU執行單元,也是程序執行過程當中的最小單元,由線程ID、程序計數器、寄存器集合和堆棧共同組成。線程的引入減少了程序併發執行時的開銷,提升了操做系統的併發性能。線程沒有本身的系統資源。線程的切換是根據調度算法時間片來的程序員

多線程的實現分爲三類:web

用戶級線程(User Level ThreadULT):對於這種線程的建立、撤消、和切換,由用戶程序來實現,內核並不知道用戶級線程的存在。算法

內核級線程(Kernel Level Thread KLT):它們是依賴於內核的,即不管是用戶進程中的線程,仍是系統進程中的線程,它們的建立、撤消、切換都由內核實現。編程

混合式線程:同時支持ULT和KLT兩種線程。api

 

3、協程安全

協程是一種比線程更加輕量級的存在,最重要的是,協程不被操做系統內核管理,協程的切換是由程序員本身調度的。網絡

運行效率極高,協程的切換徹底由程序控制,不像線程切換須要花費操做系統的開銷,線程數量越多,協程的優點就越明顯。多線程

協程不須要多線程的鎖機制,由於只有一個線程,不存在變量衝突。

對於多核CPU,利用多進程+協程的方式,能充分利用CPU,得到極高的性能。

優點:

最大的優點就是協程極高的執行效率。由於子程序切換不是線程切換,而是由程序自身控制,所以,沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優點就越明顯。

第二大優點就是不須要多線程的鎖機制,由於只有一個線程,也不存在同時寫變量衝突,在協程中控制共享資源不加鎖,只須要判斷狀態就行了,因此執行效率比多線程高不少。

 

可參考博客:https://blog.csdn.net/mieleizhi0522/article/details/82142856

 

Greenlet

greenlet是一個用C實現的協程模塊,相比與python自帶的yield,它可使你在任意函數之間隨意切換,而不需把這個函數先聲明爲generator

Gevent: (實現遇到IO自動切換)

Gevent 是一個第三方庫,能夠輕鬆經過gevent實現併發同步或異步編程,在gevent中用到的主要模式是Greenlet, 它是以C擴展模塊形式接入Python的輕量級協程。 Greenlet所有運行在主程序操做系統進程的內部,但它們被協做式地調度

 

4、區別 

一、進程多與線程比較

線程是指進程內的一個執行單元,也是進程內的可調度實體。線程與進程的區別:
1) 地址空間:線程是進程內的一個執行單元,進程內至少有一個線程,它們共享進程的地址空間,而進程有本身獨立的地址空間
2) 資源擁有:進程是資源分配和擁有的單位,同一個進程內的線程共享進程的資源
3) 線程是處理器調度的基本單位,但進程不是
4) 兩者都可併發執行

5) 每一個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口,可是線程不可以獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制

二、協程多與線程進行比較

1) 一個線程能夠多個協程,一個進程也能夠單獨擁有多個協程,這樣python中則能使用多核CPU。

2) 線程進程都是同步機制,而協程則是異步

3) 協程能保留上一次調用時的狀態,每次過程重入時,就至關於進入上一次調用的狀態

 

  • 與線程不一樣,協程是本身主動讓出CPU,並交付他指望的下一個協程運行,而不是在任什麼時候候都有可能被系統調度打斷。所以協程的使用更加清晰易懂,而且多數狀況下不須要鎖機制。
  • 與線程相比,協程的切換由程序控制,發生在用戶空間而非內核空間,所以切換的代價很是的小。
  • 某種意義上,協程與線程的關係相似與線程與進程的關係,多個協程會在同一個線程的上下文之中運行。

 

5、進程調度算法

不一樣環境的調度算法目標不一樣,所以須要針對不一樣環境來討論調度算法。

1. 批處理系統

批處理系統沒有太多的用戶操做,在該系統中,調度算法目標是保證吞吐量和週轉時間(從提交到終止的時間)。

1.1 先來先服務 first-come first-serverd(FCFS)

按照請求的順序進行調度。

有利於長做業,但不利於短做業,由於短做業必須一直等待前面的長做業執行完畢才能執行,而長做業又須要執行很長時間,形成了短做業等待時間過長。

1.2 短做業優先 shortest job first(SJF)

按估計運行時間最短的順序進行調度。

長做業有可能會餓死,處於一直等待短做業執行完畢的狀態。由於若是一直有短做業到來,那麼長做業永遠得不到調度。

1.3 最短剩餘時間優先 shortest remaining time next(SRTN)

按估計剩餘時間最短的順序進行調度。

2. 交互式系統

交互式系統有大量的用戶交互操做,在該系統中調度算法的目標是快速地進行響應。

2.1 時間片輪轉

將全部就緒進程按 FCFS 的原則排成一個隊列,每次調度時,把 CPU 時間分配給隊首進程,該進程能夠執行一個時間片。當時間片用完時,由計時器發出時鐘中斷,調度程序便中止該進程的執行,並將它送往就緒隊列的末尾,同時繼續把 CPU 時間分配給隊首的進程。

時間片輪轉算法的效率和時間片的大小有很大關係:

  • 由於進程切換都要保存進程的信息而且載入新進程的信息,若是時間片過小,會致使進程切換得太頻繁,在進程切換上就會花過多時間。

  • 而若是時間片過長,那麼實時性就不能獲得保證。

 
 

2.2 優先級調度

爲每一個進程分配一個優先級,按優先級進行調度。

爲了防止低優先級的進程永遠等不到調度,能夠隨着時間的推移增長等待進程的優先級。

2.3 多級反饋隊列

一個進程須要執行 100 個時間片,若是採用時間片輪轉調度算法,那麼須要交換 100 次。

多級隊列是爲這種須要連續執行多個時間片的進程考慮,它設置了多個隊列,每一個隊列時間片大小都不一樣,例如 1,2,4,8,..。進程在第一個隊列沒執行完,就會被移到下一個隊列。這種方式下,以前的進程只須要交換 7 次。

每一個隊列優先權也不一樣,最上面的優先權最高。所以只有上一個隊列沒有進程在排隊,才能調度當前隊列上的進程。

能夠將這種調度算法當作是時間片輪轉調度算法和優先級調度算法的結合。

 
 

3. 實時系統

實時系統要求一個請求在一個肯定時間內獲得響應。

分爲硬實時和軟實時,前者必須知足絕對的截止時間,後者能夠容忍必定的超時。

 

6、進程間通訊

參考:https://blog.csdn.net/sinat_38682860/article/details/80483533

進程間通訊(IPC,InterProcess Communication)是指在不一樣進程之間傳播或交換信息。

IPC的方式一般有管道(包括無名管道和命名管道)、消息隊列、信號量、共享存儲、Socket、Streams等。其中 Socket和Streams支持不一樣主機上的兩個進程IPC。

以Linux中的C語言編程爲例。

(1)管道pipe

  1. 它是半雙工的(即數據只能在一個方向上流動),具備固定的讀端和寫端。

  2. 它只能用於具備親緣關係的進程之間的通訊(也是父子進程或者兄弟進程之間)。

  3. 它能夠當作是一種特殊的文件,對於它的讀寫也可使用普通的read、write 等函數。可是它不是普通的文件,並不屬於其餘任何文件系統,而且只存在於內存中。

(2)消息隊列Queue

操做系統也提供了跨進程的消息隊列對象可讓咱們直接使用,只不過python沒有默認提供包裝好的api來直接使用。咱們必須使用第三方擴展來完成OS消息隊列通訊。第三方擴展是經過使用Python包裝的C實現來完成的。

OS消息隊列有兩種形式,一種是posix消息隊列,另外一種是systemv消息隊列,有些操做系統二者都支持,有些只支持其中的一個

(3)共享內存SharedMemory

共享內存也是很是常見的多進程通訊方式,操做系統負責將同一份物理地址的內存映射到多個進程的不一樣的虛擬地址空間中。進而每一個進程均可以操做這分內存。考慮到物理內存的惟一性,它屬於臨界區資源,須要在進程訪問時搞好併發控制,好比使用信號量。咱們經過一個信號量來控制全部子進程的順序讀寫共享內存。咱們分配一個8字節double類型的共享內存用來存儲極限的和,每次從共享內存中讀出來時,要使用struct進行反序列化(unpack),將新的值寫進去以前也要使用struct進行序列化(pack)。每次讀寫操做都須要將讀寫指針移動到內存開頭位置(lseek)。

(4)套接字

這是一種更爲通常得進程間通訊機制,它可用於網絡中不一樣機器之間的進程間通訊,應用很是普遍。

 

7、線程間同步

 

 

8、進程和線程、協程在python中的使用

  一、多進程通常使用multiprocessing庫,來利用多核CPU,主要是用在CPU密集型的程序上,固然生產者消費者這種也可使用。多進程的優點就是一個子進程崩潰並不會影響其餘子進程和主進程的運行,但缺點就是不能一次性啓動太多進程,會嚴重影響系統的資源調度,特別是CPU使用率和負載。使用多進程能夠查看文章《python 多進程使用總結》。注:python2的進程池在類中的使用會有問題,須要把類函數定義成全局函數。具體可參考 http://bbs.chinaunix.net/thread-4111379-1-1.html

  二、多線程通常是使用threading庫,完成一些IO密集型併發操做。多線程的優點是切換快,資源消耗低,但一個線程掛掉則會影響到全部線程,因此不夠穩定。現實中使用線程池的場景會比較多,具體可參考《python線程池實現》。

  三、協程通常是使用gevent庫,固然這個庫用起來比較麻煩,因此使用的並非不少。相反,協程在tornado的運用就多得多了,使用協程讓tornado作到單線程異步,聽說還能解決C10K的問題。因此協程使用的地方最多的是在web應用上。

總結一下就是IO密集型通常使用多線程或者多進程,CPU密集型通常使用多進程,強調非阻塞異步併發的通常都是使用協程,固然有時候也是須要多進程線程池結合的,或者是其餘組合方式。

 

9、GIL(全局解釋器鎖)

GIL加在cpython解釋器中, 其餘的python解釋器不會有GIL。

Python中的線程是操做系統的原生線程,Python虛擬機使用一個全局解釋器鎖(Global Interpreter Lock)來互斥線程對Python

虛擬機的使用。爲了支持多線程機制,一個基本的要求就是須要實現不一樣線程對共享資源訪問的互斥,因此引入了GIL。

GIL:在一個線程擁有了解釋器的訪問權以後,其餘的全部線程都必須等待它釋放解釋器的訪問權,即便這些線程的下一條指令並不

會互相影響。

在調用任何Python C API以前,要先得到GIL

GIL缺點:多處理器退化爲單處理器;優勢:避免大量的加鎖解鎖操做

不管你啓多少個線程,你有多少個cpu, Python在執行一個進程的時候會淡定的在同一時刻只容許一個線程運行。因此,python是沒法利用多核CPU實現多線程的。這樣,python對於計算密集型的任務開多線程的效率甚至不如串行(沒有大量切換),可是,對於IO密集型的任務效率仍是有顯著提高的。

相關文章
相關標籤/搜索