關於IO,你還在迷惑這些概念嗎?阻塞、非阻塞、異步、同步

在IT圈混飯吃,不管你用什麼編程語言、從事前端還是後端,阻塞、非阻塞、異步、同步這些概念,都需要清晰地掌握,否則,怎麼與面試官談笑風生(chui niu pi)?但是,掌握這些概念又不是非常容易,尤其對非科班出身的,更加困難。本文試圖給出一個清晰簡明但不失深刻的介紹,希望對大家有所幫助。

1、從I/O說起

這些概念之所以容易令人迷惑,在於很多人對I/O就沒有清晰準確的理解,後面的理解自然不可能正確。我想用一個具體的例子來說明一下I/O。 設想自己是一個進程,就叫小進吧。小進需要接收一個輸入,我們不管這個輸入是從網絡套接字來,還是鍵盤,鼠標來,輸入的來源可以千千萬萬。但是,都必須由內核來幫小進完成,為啥內核這麼霸道?因為計算機上運行的可不只是咱小進一個進程,還有很多進程。這些進程兄弟也可能需要從這些輸入設備接收輸入,沒有內核居中協調,豈不是亂套。 從小進的角度看,內核幫助它完成輸入,其實包括三個步驟:

  • 1、內核替小進接收好數據,這些數據暫時存在內核的內存空間
  • 2、內核將數據從自己的內存空間複製到小進的內存空間
  • 3、告訴小進,輸入數據來了,趕快讀吧

這三步看似挺簡單,其實在具體實現時,有很多地方需要考慮:

  • 0、小進如何告訴內核自己要接收一個輸入?
  • 1、內核接到小進的請求,替小進接收好數據這段時間, 小進咋辦?
  • 2、內核在將數據複製到小進的內存空間這段時間,小進咋辦?
  • 3、到底什麼時候告訴小進數據準備好了,是在內核接收好數據之後就告訴小進,還是在將數據複製到小進的內存空間之後再告訴他?
  • 4、內核以什麼樣的方式告訴小進,數據準備好了?

2、阻塞式I/O模型

對上面5個問題,最簡單的解決方案就是阻塞式I/O模型,它的過程是這樣的: 小進:內核內核,我要接收一個鍵盤輸入,快點幫我完成! 內核:好咧!biubiu!內核迅速將小進阻塞,可憐的小進頓時石化,就像被孫悟空點了定一樣。 就這樣,小進在石化中,時間一點點流逝。終於,內核收到了數據。 內核:數據終於來了,我要開幹了!duang duang duang,先把數據存在自己的內核空間,然後又複製到小進的用戶空間。 內核:biubiu!內核解除了小進的阻塞,小進瞬間復活,小進的記憶還是停留在讓內核幫他接收輸入時。 小進:哇!內核真靠譜,數據已經有了!幹活去!

我們可以看到,小進發出接收輸入的請求給內核開始,就處於阻塞狀態,直到內核將數據複製到小進的用戶空間,小進才解除阻塞。 以上過程可通過下圖來解釋:


關於IO,你還在迷惑這些概念嗎?阻塞、非阻塞、異步、同步

3、非阻塞式I/O

小進發現,阻塞式I/O中,自己總要被阻塞好久,好不爽啊,於是小進改用了非阻塞式I/O,其過程是這樣的: 小進:內核內核,我要接收一個輸入,趕緊幫我看看,數據到了沒有,先說好,不要阻塞我。 內核:查看了一下自己的內核空間,沒有發現數據,於是迅速告訴小進,沒有呢!並繼續幫小進等著數據。 如此這樣,小進不斷地問內核,終於,過了一段時間,小進再一次詢問時,內核往自己的空間中一查,呦!數據來了,不勝其煩的內核迅速告訴小進,數據好了! 小進:快給我! 內核:biu!內核乾淨利落地阻塞了小進,悲催的小進還是石化了! 內核趕緊將自己空間的輸入數據複製到小進的用戶空間,複製好後。 內核:biu!內核解除了小進的阻塞,小進立馬復活 小進:哇!數據來了,啥也不說,幹活!

我們看到,所謂的非阻塞I/O,其實在內核將數據從內核空間複製到小進的用戶空間時,小進還是被阻塞的。 具體過程如下圖所示:


關於IO,你還在迷惑這些概念嗎?阻塞、非阻塞、異步、同步

4、異步I/O

上面的兩種I/O解決方案中,小進都被阻塞了,只不過是阻塞時間長短不一樣,第一種方案中小進被阻塞的時間長一些,在內核接收數據以及將數據複製到小進的用戶空間時,都被阻塞。 第二種方案中,只在內核將數據從內核空間複製到小進的用戶空間時,小進才被阻塞。 我們現在說的異步I/O,目的就是讓小進絕對不被阻塞。其過程是這樣的: 小進:內核內核,我要接收一個輸入,弄好了告訴我。同時將一個信號和信號處理函數告訴內核,然後繼續幹自己的活了。 內核:得了您嘞,您先忙。 一直到內核接收到數據並將數據從內核空間複製到小進的用戶空間後,內核才給小進發送信號。小進在信號處理函數中可以直接處理數據。 其過程可用下圖解釋:


關於IO,你還在迷惑這些概念嗎?阻塞、非阻塞、異步、同步

5、IO多路複用

在上面的阻塞IO中,我們的小進都是直接阻塞在IO系統調用recvfrom上,可以說是與IO系統調用“零距離”。

這種做法有一定的弊端,就是當小進要同時等待多個輸入,哪個先來就處理哪個時,小進不知道哪個先來,自然也就不知道應該被阻塞到哪一個輸入的recvfrom上好。

聰明如你,可能會說,那全部用異步IO唄。但這樣也不方便,就是小進要為每一個輸入都在系統中註冊一個信號和信號處理函數,這可是要與內核打交道的。如果要等的輸入非常多,豈不是非常的麻煩。

為了方便處理這種情況,小進可以使用一個輸入管家,就是select系統調用,該調用可以幫助小進管理所有的輸入(通常是套接字),每當一個輸入中有數據到來時,就告訴小進。這樣小進實際上是阻塞在select系統調用上,而不是阻塞在真正的IO系統調用上,如下圖所示:


關於IO,你還在迷惑這些概念嗎?阻塞、非阻塞、異步、同步

6、那啥是同步呢?

一句話,凡是讓小進阻塞(不管長短)的I/O方案都是同步I/O。也就是說,阻塞、非阻塞、信號驅動式都是同步I/O。

7、無總結,不進步

上面,我們從完成輸入時,進程與內核的交互方式的角度分析了不同的I/O解決方案,在這個過程中,解釋清楚了阻塞、非阻塞、同步、異步的概念。


作者:milter
鏈接:https://www.jianshu.com/p/3d603166f54d
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。


分享到:


相關文章: