初識網絡並發編程
一 背景知識:
顧名思義,進程即正在執行的一個過程。進程是對正在運行程序的一個抽象。
進程的概念起源於操作系統,是操作系統最核心的概念,也是操作系統提供的最古老也是最重要的抽象概念之一。操作系統的其他所有內容都是圍繞進程的概念展開的。
操作系統的概念:
即使可以利用的cpu只有一個(早期的計算機確實如此),也能保證支持(偽)並發的能力。將一個單獨的cpu變成多個虛擬的cpu(多道技術:時間多路復用和空間多路復用+硬件上支持隔離),沒有進程的抽象,現代計算機將不復存在。
必備的理論基礎:
一 操作系統的作用:
1:隱藏醜陋復雜的硬件接口,提供良好的抽象接口 2:管理、調度進程,並且將多個進程對硬件的競爭變得有序
二 多道技術:
1.產生背景:針對單核,實現並發
ps:
現在的主機一般是多核,那麽每個核都會利用多道技術
有4個cpu,運行於cpu1的某個程序遇到io阻塞,會等到io結束再重新調度,會被調度到4個
cpu中的任意一個,具體由操作系統調度算法決定。
2.空間上的復用:如內存中同時有多道程序
3.時間上的復用:復用一個cpu的時間片
強調:遇到io切,占用cpu時間過長也切,核心在於切之前將進程的狀態保存下來,這樣
才能保證下次切換回來時,能基於上次切走的位置繼續運行
二 什麽是進程:
進程(Process)是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。在早期面向進程設計的計算機結構中,進程是程序的基本執行實體;在當代面向線程設計的計算機結構中,進程是線程的容器。程序是指令、數據及其組織形式的描述,進程是程序的實體。我們自己在python文件中寫了一些代碼,這叫做程序,運行這個python文件的時候,這叫做進程。
狹義定義:進程是正在運行的程序的實例(an instance of a computer program that is being executed)。 廣義定義:進程是一個具有一定獨立功能的程序關於某個數據集合的一次運行活動。它是操作系統動態執行的基本單元,在傳統的操作系統中,進程既是基本的分配單元,也是基本的執行單元。第一,進程是一個實體。每一個進程都有它自己的地址空間,一般情況下,包括文本區域(text region)(python的文件)、數據區域(data region)(python文件中定義的一些變量數據)和堆棧(stack region)。文本區域存儲處理器執行的代碼;數據區域存儲變量和進程執行期間使用的動態分配的內存;堆棧區域存儲著活動過程調用的指令和本地變量。 第二,進程是一個“執行中的程序”。程序是一個沒有生命的實體,只有處理器賦予程序生命時(操作系統執行之),它才能成為一個活動的實體,我們稱其為進程。[3] 進程是操作系統中最基本、重要的概念。是多道程序系統出現後,為了刻畫系統內部出現的動態情況,描述系統內部各道程序的活動規律引進的一個概念,所有多道程序設計操作系統都建立在進程的基礎上。
進程的特征:
動態性:進程的實質是程序在多道程序系統中的一次執行過程,進程是動態產生,動態消亡的。 並發性:任何進程都可以同其他進程一起並發執行 獨立性:進程是一個能獨立運行的基本單位,同時也是系統分配資源和調度的獨立單位; 異步性:由於進程間的相互制約,使進程具有執行的間斷性,即進程按各自獨立的、不可預知的速度向前推進 結構特征:進程由程序、數據和進程控制塊三部分組成。 多個不同的進程可以包含相同的程序:一個程序在不同的數據集裏就構成不同的進程,能得到不同的結果;但是執行過程中,程序不能發生改變。
進程與程序中的區別:
程序是指令和數據的有序集合,其本身沒有任何運行的含義,是一個靜態的概念。
而進程是程序在處理機上的一次執行過程,它是一個動態的概念。
程序可以作為一種軟件資料長期存在,而進程是有一定生命期的。
程序是永久的,進程是暫時的。
舉例:就像qq一樣,qq是我們安裝在自己電腦上的客戶端程序,其實就是一堆的代碼文件,我們不運行qq,那麽他就是一堆代碼程序,當我們運行qq的時候,這些代碼運行起來,就成為一個進程了。
註意:同一個程序執行兩次,就會在操作系統中出現兩個進程,所以我們可以同時運行一個軟件,分別做不同的事情也不會混亂。比如打開暴風影音,雖然都是同一個軟件,但是一個可以播放柯南,一個可以播放火影。
三 進程調度:
調度算法
要想多個進程交替運行,操作系統必須對這些進程進行調度,這個調度也不是隨即進行的,而是需要遵循一定的法則,由此就有了進程的調度算法。
先來先服務調度算法:
先來先服務(FCFS)調度算法是一種最簡單的調度算法,該算法既可用於作業調度,也可用於進程調度。FCFS算法比較有利於長作業(進程),而不利於短作業(進程)。由此可知,本算法適合於CPU繁忙型作業,而不利於I/O繁忙型的作業(進程)。
短作業優先調度算法:
短作業(進程)優先調度算法(SJ/PF)是指對短作業或短進程優先調度的算法,該算法既可用於作業調度,也可用於進程調度。但其對長作業不利;不能保證緊迫性作業(進程)被及時處理;作業的長短只是被估算出來的。
時間片輪轉法:
時間片輪轉(Round Robin,RR)法的基本思路是讓每個進程在就緒隊列中的等待時間與享受服務的時間成比例。在時間片輪轉法中,需要將CPU的處理時間分成固定大小的時間片,例如,幾十毫秒至幾百毫秒。如果一個進程在被調度選中之後用完了系統規定的時間片,但又未完成要求的任務,則它自行釋放自己所占有的CPU而排到就緒隊列的末尾,等待下一次調度。同時,進程調度程序又去調度當前就緒隊列中的第一個進程。 顯然,輪轉法只能用來調度分配一些可以搶占的資源。這些可以搶占的資源可以隨時被剝奪,而且可以將它們再分配給別的進程。CPU是可搶占資源的一種。但打印機等資源是不可搶占的。由於作業調度是對除了CPU之外的所有系統硬件資源的分配,其中包含有不可搶占資源,所以作業調度不使用輪轉法。 在輪轉法中,時間片長度的選取非常重要。首先,時間片長度的選擇會直接影響到系統的開銷和響應時間。如果時間片長度過短,則調度程序搶占處理機的次數增多。這將使進程上下文切換次數也大大增加,從而加重系統開銷。反過來,如果時間片長度選擇過長,例如,一個時間片能保證就緒隊列中所需執行時間最長的進程能執行完畢,則輪轉法變成了先來先服務法。時間片長度的選擇是根據系統對響應時間的要求和就緒隊列中所允許最大的進程數來確定的。 在輪轉法中,加入到就緒隊列的進程有3種情況: 一種是分給它的時間片用完,但進程還未完成,回到就緒隊列的末尾等待下次調度去繼續執行。 另一種情況是分給該進程的時間片並未用完,只是因為請求I/O或由於進程的互斥與同步關系而被阻塞。當阻塞解除之後再回到就緒隊列。 第三種情況就是新創建進程進入就緒隊列。 如果對這些進程區別對待,給予不同的優先級和時間片從直觀上看,可以進一步改善系統服務質量和效率。例如,我們可把就緒隊列按照進程到達就緒隊列的類型和進程被阻塞時的阻塞原因分成不同的就緒隊列,每個隊列按FCFS原則排列,各隊列之間的進程享有不同的優先級,但同一隊列內優先級相同。這樣,當一個進程在執行完它的時間片之後,或從睡眠中被喚醒以及被創建之後,將進入不同的就緒隊列。
多級反饋隊列:
前面介紹的各種用作進程調度的算法都有一定的局限性。如短進程優先的調度算法,僅照顧了短進程而忽略了長進程,而且如果並未指明進程的長度,則短進程優先和基於進程長度的搶占式調度算法都將無法使用。 而多級反饋隊列調度算法則不必事先知道各種進程所需的執行時間,而且還可以滿足各種類型進程的需要,因而它是目前被公認的一種較好的進程調度算法。在采用多級反饋隊列調度算法的系統中,調度算法的實施過程如下所述。 (1) 應設置多個就緒隊列,並為各個隊列賦予不同的優先級。第一個隊列的優先級最高,第二個隊列次之,其余各隊列的優先權逐個降低。該算法賦予各個隊列中進程執行時間片的大小也各不相同,在優先權愈高的隊列中,為每個進程所規定的執行時間片就愈小。例如,第二個隊列的時間片要比第一個隊列的時間片長一倍,……,第i+1個隊列的時間片要比第i個隊列的時間片長一倍。 (2) 當一個新進程進入內存後,首先將它放入第一隊列的末尾,按FCFS原則排隊等待調度。當輪到該進程執行時,如它能在該時間片內完成,便可準備撤離系統;如果它在一個時間片結束時尚未完成,調度程序便將該進程轉入第二隊列的末尾,再同樣地按FCFS原則等待調度執行;如果它在第二隊列中運行一個時間片後仍未完成,再依次將它放入第三隊列,……,如此下去,當一個長作業(進程)從第一隊列依次降到第n隊列後,在第n 隊列便采取按時間片輪轉的方式運行。 (3) 僅當第一隊列空閑時,調度程序才調度第二隊列中的進程運行;僅當第1~(i-1)隊列均空時,才會調度第i隊列中的進程運行。如果處理機正在第i隊列中為某進程服務時,又有新進程進入優先權較高的隊列(第1~(i-1)中的任何一個隊列),則此時新進程將搶占正在運行進程的處理機,即由調度程序把正在運行的進程放回到第i隊列的末尾,把處理機分配給新到的高優先權進程。
四 並發與並行:
通過進程之間的調度,也就是進程之間的切換,我們用戶感知到的好像是兩個視頻文件同時在播放,或者音樂和遊戲同時在進行,那就讓我們來看一下什麽叫做並發和並行
無論是並行還是並發,在用戶看來都是‘同時‘運行的,不管是進程還是線程,都只是一個任務而已,真是幹活的是cpu,cpu來做這些任務,而一個cpu同一時刻只能執行一個任務
並發:是偽並行,即看起來是同時運行。單個cpu+多道技術就可以實現並發,(並行也屬於並發)
你是一個cpu,你同時談了三個女朋友,每一個都可以是一個戀愛任務,你被這三個任務共享要玩出並發戀愛的效果, 應該是你先跟女友1去看電影,看了一會說:不好,我要拉肚子,然後跑去跟第二個女友吃飯,吃了一會說:那啥,我去趟洗手間,然後跑去跟女友3開了個房,然後在你的基友眼裏,你就在和三個女友同時在一起玩。
並行:並行:同時運行,只有具備多個cpu才能實現並行
將多個cpu比喻成高速公路上的多個車道,進程就好比每個車道上行駛的車輛,並行就是說,大家在自己的車道上行駛,會不影響,同時在開車。這就是並行
單核下,可以利用多道技術,多個核,每個核也都可以利用多道技術(多道技術是針對單核而言的)
有四個核,六個任務,這樣同一時間有四個任務被執行,假設分別被分配給了cpu1,cpu2,cpu3,cpu4,
一旦任務1遇到I/O就被迫中斷執行,此時任務5就拿到cpu1的時間片去執行,這就是單核下的多道技術
而一旦任務1的I/O結束了,操作系統會重新調用它(需知進程的調度、分配給哪個cpu運行,由操作系統說了算),可能被分配給四個cpu中的任意一個去執行
所有現代計算機經常會在同一時間做很多件事,一個用戶的PC(無論是單cpu還是多cpu),都可以同時運行多個任務(一個任務可以理解為一個進程)。
啟動一個進程來殺毒(360軟件)
啟動一個進程來看電影(暴風影音)
啟動一個進程來聊天(騰訊QQ)
所有的這些進程都需被管理,於是一個支持多進程的多道程序系統是至關重要的
多道技術概念回顧:內存中同時存入多道(多個)程序,cpu從一個進程快速切換到另外一個,使每個進程各自運行幾十或幾百毫秒,這樣,雖然在某一個瞬間,一個cpu只能執行一個任務,但在1秒內,cpu卻可以運行多個進程,這就給人產生了並行的錯覺,即偽並行,以此來區分多處理器操作系統的真正硬件並行(多個cpu共享同一個物理內存)
五 同步\異步\阻塞\非阻塞(重點)
1.進程狀態介紹
在了解其他概念之前,我們首先要了解進程的幾個狀態。在程序運行的過程中,由於被操作系統的調度算法控制,程序會進入幾個狀態:就緒,運行和阻塞。
(1)就緒(Ready)狀態
當進程已分配到除CPU以外的所有必要的資源,只要獲得處理機便可立即執行,這時的進程狀態稱為就緒狀態。
(2)執行/運行(Running)狀態當進程已獲得處理機,其程序正在處理機上執行,此時的進程狀態稱為執行狀態。
(3)阻塞(Blocked)狀態正在執行的進程,由於等待某個事件發生而無法執行時,便放棄處理機而處於阻塞狀態。引起進程阻塞的事件可有多種,例如,等待I/O完成、申請緩沖區不能滿足、等待信件(信號)等。
事件請求:input、sleep、文件輸入輸出、recv、accept等
事件發生:sleep、input等完成了
時間片到了之後有回到就緒狀態,這三個狀態不斷的在轉換。
2.同步異步
所謂同步就是一個任務的完成需要依賴另外一個任務時,只有等待被依賴的任務完成後,依賴的任務才能算完成,這是一種可靠的任務序列
。要麽成功都成功,失敗都失敗,兩個任務的狀態可以保持一致。其實就是一個程序結束才執行另外一個程序,串行的,不一定兩個程序就有依賴關系。
所謂異步是不需要等待被依賴的任務完成,只是通知被依賴的任務要完成什麽工作,依賴的任務也立即執行,只要自己完成了整個任務就算完成了
。至於被依賴的任務最終是否真正完成,依賴它的任務無法確定,所以它
是不可靠的
任務序列
。
同步異步舉例:
比如我們去樓下的老家肉餅吃飯,飯點好了,取餐的時候發生了一些同步異步的事情。 同步:我們都站在隊裏等著取餐,前面有個人點了一份肉餅,後廚做了很久,但是由於同步機制,我們還是要站在隊裏等著前面那個人的肉餅做好取走,我們才往前走一步。 異步:我們點完餐之後,點餐員給了我們一個取餐號碼,跟你說,你不用在這裏排隊等著,去找個地方坐著玩手機去吧,等飯做好了,我叫你。這種機制(等待別人通知)就是異步等待消息通知。在異步消息處理中,等待消息通知者(在這個例子中等著取餐的你)往往註冊一個回調機制,在所等待的事件被觸發時由觸發機制(點餐員)通過某種機制(喊號,‘250號你的包子好了‘)找到等待該事件的人。
3.阻塞與非阻塞
阻塞和非阻塞這兩個概念與程序(線程)等待消息通知(無所謂同步或者異步)時的狀態有關。也就是說阻塞與非阻塞主要是程序(線程)等待消息通知時的狀態角度來說的
繼續上面的那個例子,不論是排隊還是使用號碼等待通知,如果在這個等待的過程中,等待者除了等待消息通知之外不能做其它的事情,那麽該機制就是阻塞的,表現在程序中,也就是該程序一直阻塞在該函數調用處不能繼續往下執行。 相反,有的人喜歡在等待取餐的時候一邊打遊戲一邊等待,這樣的狀態就是非阻塞的,因為他(等待者)沒有阻塞在這個消息通知上,而是一邊做自己的事情一邊等待。阻塞的方法:input、time.sleep,socket中的recv、accept等等。
4.同步/異步 與 阻塞和非阻塞
同步阻塞形式
效率最低。拿上面的例子來說,就是你專心排隊,什麽別的事都不做。
異步阻塞形式
如果在排隊取餐的人采用的是異步的方式去等待消息被觸發(通知)
,也就是領了一張小紙條,假如在這段時間裏他不能做其它的事情,就在那坐著等著,不能玩遊戲等,那麽很顯然,這個人被阻塞在了這個等待的操作上面;
異步操作是可以被阻塞住的,只不過它不是在處理消息時阻塞,而是在等待消息通知時被阻塞。
同步非阻塞形式
實際上是效率低下的。
想象一下你一邊打著電話一邊還需要擡頭看到底隊伍排到你了沒有,如果把打電話和觀察排隊的位置看成是程序的兩個操作的話,這個程序需要在這兩種不同的行為之間來回的切換
,效率可想而知是低下的。
異步非阻塞形式
效率更高,
因為打電話是你(等待者)的事情,而通知你則是櫃臺(消息觸發機制)的事情,程序沒有在兩種不同的操作中來回切換
。
比如說,這個人突然發覺自己煙癮犯了,需要出去抽根煙,於是他告訴點餐員說,排到我這個號碼的時候麻煩到外面通知我一下,那麽他就沒有被阻塞在這個等待的操作上面,自然這個就是異步+非阻塞的方式了。
很多人會把同步和阻塞混淆,是因為很多時候同步操作會以阻塞的形式表現出來
,同樣的,很多人也會把異步和非阻塞混淆,因為異步操作一般都不會在真正的IO操作處被阻塞
。
初識網絡並發編程