同步異步、阻塞和非阻塞、網絡模型

一、概念

同步異步、阻塞和非阻塞是兩套概念,容易混淆。

同步異步是進程和內核之間

阻塞和非阻塞是進程在訪問數據時候,根據IO操作的就緒狀態來採取的不同方式(函數處理方式)

1.同步和異步

   同步和異步是針對應用程序和內核的交互來說的,同步指的是用戶進程觸發IO操作並等待或者輪詢的去查看IO操作是否就緒,而異步是指用戶進程觸發IO操作以後便開始做自己的事情,交給OS,而當IO操作完成時會得到IO完成的通知。

  異步:OS需要支持異步IO操作API

2.阻塞和非阻塞

   阻塞和非阻塞是進程在訪問數據時候,根據IO操作的就緒狀態來採取的不同方式,是一種讀取或者寫入操作函數的實現方式,阻塞方式下讀取或者寫入函數將一直等待,直到讀取或寫入成功;而非阻塞方式下,讀取或寫入函數會立即返回一個狀態。

  阻塞非阻塞是線程的一種狀態

 

對於同步/異步,阻塞/非阻塞的概念,網上流傳着一個小故事來介紹這個概念,相信不少同學都看過(普通水壺,簡稱水壺;會響的水壺,簡稱響水壺)

同步阻塞:小明把水壺放到火上,然後在那傻等水開。

同步非阻塞:小明把水壺放到火上,然後去客廳看電視,時不時的去廚房看看水開沒有。

異步阻塞:小明把響水壺放到火上,然後在那傻等水開。

異步非阻塞:小明把響水水壺放到火上,去客廳看電視,水壺響之前不再去看它了,響了再去處理

二、Linux網絡模型簡介


Linux的內核將所有的外部設備都看做成一個文件來操作,對一個文件的讀寫操作都會調用內核提供的系統指令,返回一個file descriptor(fd,文件描述符)。而Socket的讀寫也會有相應的描述符,稱之爲socketfd (socket描述符),這裏所說的描述符就是一個數字,指向內核中的一個結構體(文件路徑,數據區)。

Unix網絡編程對I/O模型進行了詳細的分類,Unix 提供了5種不同的模型,下面我們依次分析這五種模型。

2.1、 阻塞IO模型

阻塞IO是最常用的IO模型,在缺省的情況下,所有文件操作都是阻塞的。這裏的應用進程就是我們所說的客戶端,而內核系統就是我們服務端。簡化以後我們看下整個流程。客戶端調用服務端請求數據,服務端收到客戶端的請求過後,首先會檢查其內核中是否有數據,沒有數據就一直等待。等待內核中有數據之後,將內核中的數據發送給客戶端。

流程分析:
整個過程客戶端請求服務端的過程中,一直處於阻塞狀態。而服務端對於客戶端來說是同步的(同步方法調用一旦開始,調用者必須等到方法調用返回後,才能繼續後續的行爲),客戶端必須等待其執行結果。而不是服務端拿到數據之後異步通知。

總結:
所以阻塞IO是一個同步阻塞的IO。

2.2、 非阻塞IO模型

非阻塞IO,客戶端調用服務器獲取數據,如果服務端(內核緩衝區)中沒有數據,直接返回EWOULDBLOCK錯誤,此時客戶端不斷的輪詢服務端是否有數據準備好。如果服務端有數據準備好了,直接複製數據。

流程分析:整個非阻塞IO和阻塞IO的區別就是,客戶端去請求數據。在阻塞模式下,客戶端一直等待,任何事情都不去做。而在非阻塞模式下,客戶端隔段時間去看下有沒有數據完成,那麼這個過程中,中間間隔的時間,就可以去做一下自己想做的事情。當然整個過程中,服務端還是同步的。

總結:通過上面的分析,異步IO模式是:同步非阻塞

2.3、 I/O複用模型

IO複用模型,Linux提供了select/poll/epoll,進程通過將一個或者多個fd傳遞給select或者poll系統調用。阻塞在select操作上,這樣select/poll 可以幫助我們偵測多個fd是否處於就緒狀態。由於select/poll是順序掃描fd是否就緒,而且支持fd的數量是有限制的。Linux還提供了一個epoll系統調用。epoll使用是基於事件驅動方式代替順序掃描,因此性能更高。

在Linux中,所有的設備操作都是操作文件,所以每個socket連接,相當於操作一個socketfd。在同步阻塞的IO中,爲了提高併發度,會爲每個socket連接分配一個線程去處理。這樣在高併發的情況下,導致系統存在大量的線程,從而使可用性下降。爲了解決這個問題,Linux底層把那些建立起連接的socketfd,提交給系統底層的epoll進行管理。每次系統調用的時候,只會把那些已經發生某些事件的socket連接批量發送給客戶端,在這種情況下只需要用一個線程去監控所有socket可能存在的狀態。把那些已經發生事件的socket提取出來,放到一個list集合中,批量發送給客戶端。客戶端根據socket的具體事件,去做相應的處理。

這個也是netty底層所實現的核心思想

總結:linux系統將已經發生事件的socket連接,打包發送給客戶端。客戶端在調用的時候,只需要拿到那些發生事件的socket,然後進行處理。

2.4、信號驅動I/O模型

首先開啓套接口信號驅動I/O功能,並通過系統調用singaction執行一個信號處理函數(此係統調用,理解返回,進程繼續工作,它是非阻塞的)。當數據準備就緒時,就爲該進程生產一個sigio信號,通過信號回調通知應用程序調用recvfrom來讀取數據。並通知主循環函數處理數據。

總結:整個過程,客戶端處於非阻塞狀態,服務端有數據的時候,通知客戶端獲取數據,是異步狀態。所以信號驅動I/O模型是異步非阻塞模型。

2.5 異步 I/O

客戶端告知服務端要啓動某個操作,並讓內核在整個操作完成一個(包括數據從內核複製到用戶空間)通知我們。這種模式與信號驅動的主要區別是:信號驅動由內核通知我們合適開始一個I/O操作,用戶還是需要自己去調用recvfrom,去拷貝數據(從內核空間拷貝到用戶空間)。而異步I/O已經完成了所有的動作,通知用戶去獲取數據即可。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章