同步 非同步和阻塞 非阻塞

2021-09-11 03:10:22 字數 3554 閱讀 3220

一、三種io

bio(同步阻塞式io):同步阻塞式io,伺服器實現模式為乙個連線乙個執行緒,即客戶端有連線請求時伺服器就需要啟動乙個執行緒進行處理,如果這個連線不做任何事情會造成不必要的執行緒開銷,可以通過執行緒池的機制改善。

nio(同步非阻塞式io):同步非阻塞式io,伺服器實現模式為乙個請求乙個執行緒,即客戶端傳送的連線請求都會註冊到多路復用器上,多路復用器輪詢到連線有i/o請求時才啟動乙個執行緒去處理

aio(非同步非阻塞式io):非同步非阻塞式io,伺服器實現模式為乙個有效請求乙個執行緒,客戶端的i/o請求都是由os先完成了在通知伺服器去啟動執行緒進行處理。

二、五種模型

一般來說,程式進行輸入操作有兩步:

等待有資料可讀

將資料從系統核心拷貝到程式的資料區

對於socket程式設計來說:

第一步:一般來說是等待資料從網路上傳到本地。當資料報到達的時候,資料將會從網路層拷貝到核心的快取中;

第二步:是從核心中把資料拷貝到程式的資料區

1.阻塞

在linux中預設情況下所有的socket都是阻塞的,當使用者程序呼叫了recvfrom這個系統呼叫,核心就開始了io的第乙個階段:準備資料。對networkio來說,很多時候資料在一開始還沒有到達(比如,還沒有收到乙個完整的udp包),這個時候核心就要等待足夠的資料到來。而在使用者程序這邊,整個程序會被阻塞。當核心乙個等到資料準備好了,它就會將資料從核心中拷貝到使用者記憶體,然後核心返回結果,使用者程序才接觸block的狀態,重新執行起來。所以,blocking io特點就是在io執行的兩個階段都被block了。

2.非阻塞

當乙個應用程式使用了非阻塞模式的套接字,它需要使用乙個迴圈來不停的測試是否乙個檔案描述符有資料可讀。應用程式不停polling核心來檢查是否i/o操作已經就緒。這將是乙個極浪費cpu資源的操作。這種模式使用不是很普遍。

linux下,可以通過設定socket使其變為非阻塞。當使用者程序發出read操作時,如果核心中的資料還沒有準備好,那麼它並不會阻塞使用者程序,而是立刻返回乙個error。從使用者程序角度來講,它發起乙個read操作後,並不需要等待,而是馬上就的到了乙個結果。使用者程序判斷結果是乙個error時,它就知道資料還沒有準備好,於是它可以再次傳送read操作。一旦核心中的資料準備好了,並且又再次收到了使用者程序的系統呼叫,那麼它馬上就將資料拷貝到了使用者記憶體(這段時間使用者程序是阻塞的),然後返回。所以使用者程序其實是需要不斷的主動輪詢核心資料好了沒有。對管道的操作,最好使用非阻塞方式。

3.多路復用

io多路復用這個詞可能有點陌生,但是如果我說select、epoll,大概就能明白了。有些地方也稱這種io方式為event driver io。我們都知道,select/epoll的好處就在於單個應用程序就可以同時處理多個網路連線的io。它的基本原理就是select/epoll這個function會不斷的輪詢所負責的所有socket,當某個socket有資料到達了,就通知使用者程序。

當使用者程序呼叫了select,那麼整個程序會被block,而同時,核心會「監視」所有select負責的socket,當任何乙個socket中的資料準備好了,select就會返回。這個時候使用者程序再呼叫read操作,將資料從kernel拷貝到使用者程序。

這個圖和阻塞io其實沒什麼太到的不同,事實上,還更差一些。因為這裡需要使用兩個系統呼叫select和recvfrom,而阻塞io只呼叫了乙個系統呼叫recvfrom。但是,用select的優勢在於它可以同時處理多個connection。如果在連線數不是很大的情況下,使用select/epoll的web server不一定比使用多執行緒+blocking io的效能要好。select/epoll的優勢並不是對於單個連線能處理的更快,而是在於能處理更多的連線。

在多路復用中,實際中,對於每乙個socket,一般都設定成非阻塞,但是,如上圖所示,整個使用者的程序其實一直被阻塞,只不過程序是被select這個函式阻塞,而不是被socket io給阻塞。

多路復用技術一般在下面這些情況中被使用:

(1)當乙個客戶端需要同時處理多個檔案描述符的輸入輸出操作的時候(一般來說是標準的輸入輸出和網路套接字 )

(2)當程式需要同時進行多個套接字操作的時候

(3)如果乙個tcp伺服器程式同時處理正在偵聽網路連線的套接字和已經連線好的套接字

(4)如果乙個伺服器程式同時使用tcp和udp協議

(5)如果乙個伺服器同時使用多種服務並且每種服務可能使用不同的協議

4.訊號驅動

5.非同步

使用者程序發起read操作之後,立刻就可以開始去做其它的事。而另一方面,從核心的角度,當它收到乙個asynchronous read之後,首先它會立刻返回,所以不會對使用者程序產生任何block。然後,核心會等資料準備完成,然後將資料拷貝到使用者記憶體,當這一切都完成之後,核心會給使用者程序傳送乙個signal,告訴它read操作完成了。

非同步io和訊號驅動io的區別:

(1)訊號驅動io模式下,由核心通知我們何時可以啟動乙個i/o操作。

(2)非同步io模式下,有核心通知我們i/o何時完成

6.同步與非同步的區別

兩者的區別就在於同步io做「io操作」的時候會將process阻塞。

按照這個定義,之前所述的阻塞io,非阻塞io,io多路復用、訊號驅動都屬於同步io。有人可能會說,非阻塞io並沒有被block啊。這裡有個非常「狡猾」的地方,定義中所指的「io操作」是指真實的io操作,就是例子中的recvfrom這個system call。非阻塞io在執行recvfrom這個system call的時候,如果核心的資料沒有準備好,這時候不會block程序。但是,當核心中資料準備好的時候,recvfrom會將資料從核心拷貝到使用者記憶體中,這個時候程序被block,在這段時間內,程序是被block的。而非同步io則不一樣,當程序發起io操作之後,就直接返回再也不理睬了,直到核心傳送乙個訊號,告訴程序說io完成。在整個過程中,程序完全沒有被block。

經過上面的介紹,會發現非阻塞io和非同步io的區別還是明顯的。在非阻塞io中,雖然程序大部分時間都不會被block,但是它仍然要求程序主動的check,並且當資料準備完成以後,也需要程序主動的再次呼叫recvfrom來將資料拷貝到使用者記憶體。而非同步io則完全不同,它就像是使用者程序將整個io操作交給了他人(核心)完成,然後他人做完後發訊號通知。在此期間,使用者程序不需要去檢查io操作的狀態,也不需要主動的去拷貝資料。

有的地方說io多路復用、訊號驅動兩種io模式屬於非同步io,原因是io多路復用程序是被select這個函式block,而不是被socket io給block,但是仔細看,io多路復用、訊號驅動在執行io操作的時候(定義中所指「io操作」是指真實的io操作,就是例子中的recvfrom這個system call系統呼叫)請求的時候,都是被阻塞的,因此io多路復用、訊號驅動屬於同步io。

同步 非同步 阻塞和非阻塞

同步 非同步 阻塞和非阻塞 在進行windowsapi winsock 網路程式設計時,我們常常見到同步 非同步 阻塞和非阻塞四種呼叫方式。這些方式其實都可以擴充套件為廣義的概念,幫助我們理解多執行緒,多程序,實時作業系統等更廣的概念。同步 synchronic 所謂同步,就是在發出乙個功能呼叫時,...

同步 非同步 阻塞和非阻塞

在進行網路程式設計時,我們常常見到同步 非同步 阻塞和非阻塞四種呼叫方式。這些方式彼此概念並不好理解。所謂同步,就是在發出乙個功能呼叫時,在沒有得到結果之前,該呼叫就不返回。按照這個定義,其實絕大多數函式都是同步呼叫 例如sin,isdigit等 但是一般而言,我們在說同步 非同步的時候,特指那些需...

同步 非同步 阻塞和非阻塞

這幾個概念總是記了又忘。寫下來。同步和非同步是針對應用程式和核心的互動而言的 同步指的是使用者程序觸發io操作並等待或者輪詢的去檢視io操作是否就緒,非同步是指使用者程序觸發io操作以後便開始做自己的事情,而當io操作已經完成的時候會得到io完成的通知。阻塞和非阻塞是針對於程序在訪問資料的時候,根據...