關於IO的同步,異步,阻塞,非阻塞

上次寫了一篇文章:Unix IO 模型學習。恰巧在此次週會的時候,@fp1203  (goldendoc成員之一) 正好在講解poll和epoll的底層實現。中途正好討論了網絡IO的同步、異步、阻塞、非阻塞的概念,當時講下來,你們的理解各不相同,互不相讓。搜索了網絡上的一些文章,觀點也各不相同,甚至連wiki也將異步和非阻塞當成一個概念在解釋。java

雖然網絡上充斥了大量關於同步、異步、阻塞、非阻塞的文章,但大都是抄來抄去,沒有一個權威的說法。但我找到了這一篇文章,該文章引用了《UNIX網絡編程 卷1》的介紹,這本書的做者是Richard Stevens。若是有Richard Stevens在這方面的定義或者結論,那麼我想,這應該是比較有說服力的了。node

關於《UNIX網絡編程 卷1》這本書,我特地找了英文原版,也共享出來了:你們能夠下載《UNIX網絡編程 卷1》的英文原版(CHM格式)。編程

我看了6.2這節內容,這節內容就是講IO模型的。剛剛提到的那篇文章,幾乎就是翻譯這個6.2節的。應該說,這個6.2節,對同步和異步的講解,算是很清楚的。網絡

下面是我本身理解的重點。異步

IO模型

目前unix存在五種IO模型(這也和上一篇文章:Unix IO 模型 中提到的一致),分別是:async

  • 阻塞型 IO(blocking I/O)
  • 非阻塞性IO(nonblocking I/O)
  • IO多路複用(I/O multiplexing)
  • 信號驅動IO(signal driven I/O)
  • 異步IO(asynchronous I/O)

IO的兩個階段

  1. 等待數據準備好
  2. 將數據從內核緩衝區複製到用戶進程緩衝區

同步,異步的區別

那麼究竟什麼是同步和異步的區別呢?請重點讀一下原文6.2節中的信號驅動IO和異步IO中的比較。最後總結出來是:函數

  • 同步IO,須要用戶進程主動將存放在內核緩衝區中的數據拷貝到用戶進程中。
  • 異步IO,內核會自動將數據從內核緩衝區拷貝到用戶緩衝區,而後再通知用戶。

這樣,同步和異步的概念就很是明顯了。以上的五種IO模型,前面四種都是同步的,只有第五種IO模型纔是異步的IO。學習

阻塞和非阻塞

那麼阻塞和非阻塞呢?注意到以上五個模型。阻塞IO,非阻塞IO,只是上面的五個模型中的兩個。阻塞,非阻塞,是針對單個進程而言的。spa

當對多路複用IO進行調用時,好比使用poll。需注意的是,poll是系統調用,當調用poll的時候,其實已是陷入了內核,是內核線程在跑了。所以對於調用poll的用戶進程來說,此時是阻塞的。.net

由於poll的底層實現,是去掃描每一個文件描述符(fd),而若是要對感興趣的fd進行掃描,那麼只能將每一個描述符設置成非阻塞的形式(對於用戶進程來說,設置fd是阻塞仍是非阻塞,可使用系統調用fcntl),這樣纔有可能進行掃描。若是掃描當中,發現有可讀(若是可讀是用戶感興趣的)的fd,那麼select就在用戶進程層面就會返回,而且告知用戶進程哪些fd是可讀的。

這時候,用戶進程仍然須要使用read的系統調用,將fd的數據,從內核緩衝區拷貝到用戶進程緩衝區(這也是poll爲同步IO的緣由)。

那麼此時的read是阻塞仍是非阻塞呢?這就要看fd的狀態了,若是fd被設置成了非阻塞,那麼此時的read就是非阻塞的;若是fd被設置成了阻塞,那麼此時的read就是阻塞的。

不過程序已經執行到了這時候,無論fd是阻塞仍是非阻塞,都沒有任何區別,由於以前的poll,就是知道有數據準備好了才返回的,也就是說內核緩衝區已經有了數據,此時進行read,是確定可以將數據拷貝到用戶進程緩衝區的。

但若是換種想法,若是poll是由於超時返回的,而咱們又對一個fd(此fd是被poll輪詢過的)進行read調用,那麼此時是阻塞仍是非阻塞,就很是有意義了,對吧!

結論

  1. 判斷IO是同步仍是異步,是看誰主動將數據拷貝到用戶進程。
  2. select或者poll,epoll,是同步調用,進行此調用的用戶進程也處於阻塞狀態。
  3. javaScript或者nodejs中的讀取網絡(文件)數據,而後提供回調函數進行處理,是異步IO。
相關文章
相關標籤/搜索