IO之同步 非同步 阻塞 非阻塞

2022-03-16 05:43:56 字數 3186 閱讀 1579

stevens在文章中一共比較了五種io model:

blocking io

nonblocking io

io multiplexing

signal driven io

asynchronous io

由於signal driven io在實際中並不常用,所以我這只提及剩下的四種io model。

再說一下io發生時涉及的物件和步驟。

對於乙個network io (這裡我們以read舉例),它會涉及到兩個系統物件,乙個是呼叫這個io的process (or thread),另乙個就是系統核心(kernel)。當乙個read操作發生時,它會經歷兩個階段:

1 等待資料準備 (waiting for the data to be ready)

2 將資料從核心拷貝到程序中 (copying the data from the kernel to the process)

記住這兩點很重要,因為這些io model的區別就是在兩個階段上各有不同的情況。

blocking io

當使用者程序呼叫了recvfrom這個系統呼叫,kernel就開始了io的第乙個階段:準備資料。對於network io來說,很多時候資料在一開始還沒有到達(比如,還沒有收到乙個完整的udp包),這個時候kernel就要等待足夠的資料到來。而在使用者程序這邊,整個程序會被阻塞。當kernel一直等到資料準備好了,它就會將資料從kernel中拷貝到使用者記憶體,然後kernel返回結果,使用者程序才解除block的狀態,重新執行起來。

所以,blocking io的特點就是在io執行的兩個階段都被block了。

non-blocking io

linux下,可以通過設定socket使其變為non-blocking。當對乙個non-blocking socket執行讀操作時,流程是這個樣子:

從圖中可以看出,當使用者程序發出read操作時,如果kernel中的資料還沒有準備好,那麼它並不會block使用者程序,而是立刻返回乙個error。從使用者程序角度講 ,它發起乙個read操作後,並不需要等待,而是馬上就得到了乙個結果。使用者程序判斷結果是乙個error時,它就知道資料還沒有準備好,於是它可以再次傳送read操作。一旦kernel中的資料準備好了,並且又再次收到了使用者程序的system call,那麼它馬上就將資料拷貝到了使用者記憶體,然後返回。

所以,使用者程序其實是需要不斷的主動詢問kernel資料好了沒有。

io multiplexing

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

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

這個圖和blocking io的圖其實並沒有太大的不同,事實上,還更差一些。因為這裡需要使用兩個system call (select 和 recvfrom),而blocking io只呼叫了乙個system call (recvfrom)。但是,用select的優勢在於它可以同時處理多個connection。(多說一句。所以,如果處理的連線數不是很高的話,使用select/epoll的web server不一定比使用multi-threading + blocking io的web server效能更好,可能延遲還更大。select/epoll的優勢並不是對於單個連線能處理得更快,而是在於能處理更多的連線。)

在io multiplexing model中,實際中,對於每乙個socket,一般都設定成為non-blocking,但是,如上圖所示,整個使用者的process其實是一直被block的。只不過process是被select這個函式block,而不是被socket io給block。

asynchronous i/o

linux下的asynchronous io其實用得很少。先看一下它的流程:

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

到目前為止,已經將四個io model都介紹完了。現在回過頭來回答最初的那幾個問題:blocking和non-blocking的區別在哪,synchronous io和asynchronous io的區別在哪。

先回答最簡單的這個:blocking vs non-blocking。前面的介紹中其實已經很明確的說明了這兩者的區別。呼叫blocking io會一直block住對應的程序直到操作完成,而non-blocking io在kernel還準備資料的情況下會立刻返回。

各個io model的比較如圖所示:

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

最後,再舉幾個不是很恰當的例子來說明這四個io model:

有a,b,c,d四個人在釣魚:

a用的是最老式的魚竿,所以呢,得一直守著,等到魚上鉤了再拉桿;

b的魚竿有個功能,能夠顯示是否有魚上鉤,所以呢,b就和旁邊的mm聊天,隔會再看看有沒有魚上鉤,有的話就迅速拉桿;

c用的魚竿和b差不多,但他想了乙個好辦法,就是同時放好幾根魚竿,然後守在旁邊,一旦有顯示說魚上鉤了,它就將對應的魚竿拉起來;

d是個有錢人,乾脆僱了乙個人幫他釣魚,一旦那個人把魚釣上來了,就給d發個簡訊。

**:

IO 同步,非同步,阻塞,非阻塞

參考文章 好文推薦 唉最近真是高產似母豬,剛進新公司工作量暫時不飽和,只能每天學學學學學學查漏補缺啦,學習使我快樂哈哈哈哈哈哈哈哈 標題裡的詞彙相信都經常看到,但是能說清楚的估計20個人裡面能有1個就不錯了,網上的資料也是五花八門,大部分描述差不多,很多時候估計作者本身也是似懂非懂,我也看了很多文章...

同步 非同步 阻塞 非阻塞 I O

一 同步 非同步 首先要是多個事物,只有乙個事物,是不存在同步或非同步的。同步 指協同步調。即,多個事物不能同時進行,必須乙個乙個的來,上乙個事物結束後,下乙個事物才開始。那當乙個事物正在進行時,其他事物在幹嘛呢?嚴格來講並沒有要求,但一般都處於 等待 狀態,因為後面事物的正常進行都需要依賴前面事物...

同步非同步IO,阻塞非阻塞

同步io操作 導致請求程序阻塞,知道io操作完成。非同步io操作 不導致程序阻塞。在處理 網路 io 的時候,阻塞和非阻塞都是同步io,阻塞,就是呼叫我 函式 我 函式 沒有接收完資料或者沒有得到結果之前,我不會返回。非阻塞,就是呼叫我 函式 我 函式 立即返回,通過select通知呼叫者 阻塞與非...