深入了解幾種IO模型(阻塞非阻塞,同步非同步)

2022-06-06 22:48:10 字數 1499 閱讀 5047

先說阻塞與非阻塞的區別,recv()函式預設是阻塞的,什麼是阻塞呢?就是當你呼叫recv()函式時,整個程序或者執行緒就等待在這裡了,直到你recv的fd的所有資訊都被send過來,這麼做好處就是保證所有資訊都能夠完整的讀取了,但劣勢也很明顯,就是在recv()的過程中你的程序或執行緒做不了其它事情,由此,引入了非阻塞io。

非阻塞io是什麼呢,還是以recv()函式為例,當你將其設定為非阻塞時,每次當你recv()時,就直接返回,不管資訊有沒有完全send進來,好處很明顯,recv()了之後程序馬上能處理下一行**,壞處也很明顯,就是你不知道你的訊息是否讀完了,這種問題就是tcp中大名鼎鼎的半包問題(解決辦法主要是通過乙個buffer快取所有讀進來的訊息)

打乙個比方,你要去開水房接3/4杯水,在阻塞情況下,你需要等待你的杯子接夠量,你才可以離開,當水是斷斷續續的時候,你就浪費了很多時間,因為在沒水的這段時間你不能做其它事情,好處就是所有水接完就是剛剛好的3/4杯,在非阻塞情況下,你每次接水就接一些,只要沒水了你就可以離開去做其它的事情,但需要你自己去看好量是不是夠了3/4杯。阻塞和非阻塞的i/o模型圖示如下:

阻塞io模型:

非阻塞io模型:

下面再說同步與非同步的區別,在posix定義中把同步io操作定義為導致程序阻塞直到io完成的操作,反之則是非同步io,看概念感覺非同步跟非阻塞好像也沒有什麼區別,要好好理解同步和非同步,就要詳細說明下io過程:

io過程主要分兩個階段:

1.資料準備階段

2.核心空間複製回使用者程序緩衝區空間

無論阻塞式io還是非阻塞式io,都是同步io模型,區別就在與第一步是否完成後才返回,但第二步都需要當前程序去完成,非同步io呢,就是從第一步開始就返回,直到第二步完成後才會返回乙個訊息,也就是說,非阻塞能夠讓你在第一步時去做其它的事情,而真正的非同步io能讓你第二步的過程也能去做其它事情。這裡就在說一下select,poll和epoll這幾個io復用方式,這時你就會了解它們為什麼是同步io了,以epoll為例,在epoll開發的伺服器模型中,epoll_wait()這個函式會阻塞等待就緒的fd,將就緒的fd拷貝到epoll_events集合這個過程中也不能做其它事(雖然這段時間很短,所以epoll配合非阻塞io是很高效也是很普遍的伺服器開發模式--同步非阻塞io模型)。有人把epoll這種方式叫做同步非阻塞(nio),因為使用者執行緒需要不停地輪詢,自己讀取資料,看上去好像只有乙個執行緒在做事情,也有人把這種方式叫做非同步非阻塞(aio),因為畢竟是核心執行緒負責掃瞄fd列表,並填充事件鍊錶的,個人認為真正理想的非同步非阻塞,應該是核心執行緒填充事件鍊錶後,主動通知使用者執行緒,或者呼叫應用程式事先註冊的**函式來處理資料,如果還需要使用者執行緒不停的輪詢來獲取事件資訊,就不是太完美了,所以也有不少人認為epoll是偽aio,還是有道理的。

再生動一點,還是以接水為例,當你使用epoll的io復用時,相當於接水方有了乙個服務員,他會告訴你哪些水龍頭有水可以接,然後你可以阻塞或者非阻塞(最好是非阻塞,不然epoll的意義就不大了)的去接水,但接水這個過程,還是要你自己完成。而非同步的io模型呢,相當於你去水房,直接把水杯遞給服務員,讓他給你接好後再通知你來,連線水的過程也不需要了,非同步io的模型如下圖:

非阻塞IO模型

include include include include include include in.h include include include include include using namespace std define maxsize 2048std queue socketqu...

io模型 非阻塞模型

linux下,可以通過設定socket使其變為non blocking。當對乙個non blocking socket執行讀操作時,流程是這個樣子 從圖中可以看出,當使用者程序發出read操作時,如果kernel中的資料還沒有準備好,那麼它並不會block使用者程序,而是立刻返回乙個error。從使...

阻塞I O,非阻塞I O

拿 socket舉例。當read資料時,如果這時沒有資料可讀,阻塞i o會一直等待有資料讀,資料從kernel copy 到socket的buffer後返回 非阻塞i o會立即返回,但如果有資料可讀,非阻塞i o也是等資料從kernel copy 到socket的buffer後返回。以上是阻塞與非阻...