1. 程式人生 > >同步IO和非同步IO、阻塞IO和非阻塞IO

同步IO和非同步IO、阻塞IO和非阻塞IO

1、IO

       IO (Input/Output,輸入/輸出)即資料的讀取(接收)或寫入(傳送)操作,通常使用者程序中的一個完整IO分為兩階段:使用者程序空間<-->核心空間、核心空間<-->裝置空間(磁碟、網路等)IO有記憶體IO、網路IO和磁碟IO三種,通常我們說的IO指的是後兩者。

       LINUX中程序無法直接操作I/O裝置,其必須通過系統呼叫請求kernel來協助完成I/O動作;核心會為每個I/O裝置維護一個緩衝區。

       對於一個輸入操作來說,程序IO系統呼叫後,核心會先看緩衝區中有沒有相應的快取資料,沒有的話再到裝置中讀取,因為裝置IO一般速度較慢,需要等待;核心緩衝區有資料則直接複製到程序空間。

       所以,對於一個網路輸入操作通常包括兩個不同階段:

(1)等待網路資料到達網絡卡→讀取到核心緩衝區,資料準備好;

(2)從核心緩衝區複製資料到程序空間。

2、5種IO模型

       《UNIX網路程式設計》說得很清楚,5種IO模型分別是阻塞IO模型、非阻塞IO模型、IO複用模型、訊號驅動的IO模型、非同步IO模型;前4種為同步IO操作,只有非同步IO模型是非同步IO操作。下面這樣些圖,是它裡面給出的例子:接收網路UDP資料的流程在IO模型下的分析,在它的基礎上再加以簡單描述,以區分這些IO模型。

2-1、阻塞IO模型

      

程序發起IO系統呼叫後,程序被阻塞,轉到核心空間處理,整個IO處理完畢後返回程序。操作成功則程序獲取到資料。

1、典型應用:阻塞socket、Java BIO;

2、特點:

程序阻塞掛起不消耗CPU資源,及時響應每個操作

實現難度低、開發應用較容易;

適用併發量小的網路應用開發;

不適用併發量大的應用:因為一個請求IO會阻塞程序,所以,得為每請求分配一個處理程序(執行緒)以及時響應,系統開銷大。

2-2、非阻塞IO模型

       程序發起IO系統呼叫後,如果核心緩衝區沒有資料,需要到IO裝置中讀取,程序返回一個錯誤而不會被阻塞;程序發起IO系統呼叫後,如果核心緩衝區有資料,核心就會把資料返回程序。

       對於上面的阻塞IO模型來說,核心資料沒準備好需要程序阻塞的時候,就返回一個錯誤,以使得程序不被阻塞。

1、典型應用:socket是非阻塞的方式(設定為NONBLOCK)

2、特點:

程序輪詢(重複)呼叫,消耗CPU的資源

實現難度低、開發應用相對阻塞IO模式較難;

 適用併發量較小、且不需要及時響應的網路應用開發;

2-3、IO複用模型

       多個的程序的IO可以註冊到一個複用器(select)上,然後用一個程序呼叫該select, select會監聽所有註冊進來的IO;

       如果select沒有監聽的IO在核心緩衝區都沒有可讀資料,select呼叫程序會被阻塞;而當任一IO在核心緩衝區中有可資料時,select呼叫就會返回;

       而後select呼叫程序可以自己或通知另外的程序(註冊程序)來再次發起讀取IO,讀取核心中準備好的資料。

       可以看到,多個程序註冊IO後,只有另一個select呼叫程序被阻塞。

1、典型應用:select、poll、epoll三種方案,nginx都可以選擇使用這三個方案;Java NIO;

2、特點:

專一程序解決多個程序IO的阻塞問題,效能好Reactor模式;

實現、開發應用難度較大;

適用高併發服務應用開發:一個程序(執行緒)響應多個請求

3、select、poll、epoll

Linux中IO複用的實現方式主要有select、poll和epoll:

Select:註冊IO、阻塞掃描,監聽的IO最大連線數不能多於FD_SIZE;

Poll:原理和Select相似,沒有數量限制,但IO數量大掃描線性效能下降;

Epoll :事件驅動不阻塞,mmap實現核心與使用者空間的訊息傳遞,數量很大,Linux2.6後核心支援;

 2-4、訊號驅動IO模型

       當程序發起一個IO操作,會向核心註冊一個訊號處理函式,然後程序返回不阻塞;當核心資料就緒時會發送一個訊號給程序,程序便在訊號處理函式中呼叫IO讀取資料。

       1、特點:回撥機制,實現、開發應用難度大;

2-5、非同步IO模型

       當程序發起一個IO操作,程序返回(不阻塞),但也不能返回果結;核心把整個IO處理完後,會通知程序結果。如果IO操作成功則程序直接獲取到資料

1、典型應用:JAVA7 AIO、高效能伺服器應用

2、特點:

不阻塞,資料一步到位Proactor模式

需要作業系統的底層支援,LINUX 2.5 版本核心首現,2.6 版本產品的核心標準特性;

實現、開發應用難度大;

非常適合高效能高併發應用;

3、IO模型比較

3-1、阻塞IO呼叫和非阻塞IO呼叫、阻塞IO模型和非阻塞IO模型

       注意這裡的阻塞IO呼叫和非阻塞IO呼叫不是指阻塞IO模型和非阻塞IO模型:

阻塞IO呼叫 :在使用者程序(執行緒)中呼叫執行的時候,程序會等待該IO操作,而使得其他操作無法執行。

非阻塞IO呼叫:在使用者程序中呼叫執行的時候,無論成功與否,該IO操作會立即返回,之後程序可以進行其他操作(當然如果是讀取到資料,一般就接著進行資料處理)。

       這個直接理解就好,程序(執行緒)IO呼叫會不會阻塞程序自己。所以這裡兩個概念是相對呼叫程序本身狀態來講的。

       從上面對比圖片來說,阻塞IO模型是一個阻塞IO呼叫,而非阻塞IO模型是多個非阻塞IO呼叫+一個阻塞IO呼叫,因為多個IO檢查會立即返回錯誤,不會阻塞程序。

       而上面也說過了,非阻塞IO模型對於阻塞IO模型來說區別就是,核心資料沒準備好需要程序阻塞的時候,就返回一個錯誤,以使得程序不被阻塞。

3-2、同步IO和非同步IO

同步IO:導致請求程序阻塞,直到I/O操作完成。

非同步IO:不導致請求程序阻塞。

       上面兩個定義是《UNIX網路程式設計 卷1:套接字聯網API》給出的。這不是很好理解,我們來擴充套件一下,先說說同步和非同步,同步和非同步關注的是雙方的訊息通訊機制

同步:雙方的動作是經過雙方協調的,步調一致的。

非同步:雙方並不需要協調,都可以隨意進行各自的操作。

       這裡我們的雙方是指,使用者程序和IO裝置;明確同步和非同步之後,我們在上面網路輸入操作例子的基礎上,進行擴充套件定義:

同步IO使用者程序發出IO呼叫,去獲取IO裝置資料,雙方的資料要經過核心緩衝區同步,完全準備好後,再複製返回到使用者程序。而複製返回到使用者程序會導致請求程序阻塞,直到I/O操作完成。

非同步IO使用者程序發出IO呼叫,去獲取IO裝置資料,並不需要同步,核心直接複製到程序,整個過程不導致請求程序阻塞。

      所以, 阻塞IO模型、非阻塞IO模型、IO複用模型、訊號驅動的IO模型者為同步IO模型,只有非同步IO模型是非同步IO。

<script>
    (function () {
        function setArticleH(btnReadmore, posi) {
            var winH = $(window).height();
            var articleBox = $("div.article_content");
            var artH = articleBox.height();
            if (artH > winH * posi) {
                articleBox.css({
                    'height': winH * posi + 'px',
                    'overflow': 'hidden'
                })
                btnReadmore.click(function () {
                    if (typeof window.localStorage === "object" && typeof window.csdn.anonymousUserLimit === "object") {
                        if (!window.csdn.anonymousUserLimit.judgment()) {
                            window.csdn.anonymousUserLimit.Jumplogin();
                            return false;
                        } else if (!currentUserName) {
                            window.csdn.anonymousUserLimit.updata();
                        }
                    }

                    articleBox.removeAttr("style");
                    $(this).parent().remove();
                })
            } else {
                btnReadmore.parent().remove();
            }
        }

        var btnReadmore = $("#btn-readmore");
        if (btnReadmore.length > 0) {
            if (currentUserName) {
                setArticleH(btnReadmore, 3);
            } else {
                setArticleH(btnReadmore, 1.2);
            }
        }
    })()
</script>
</article>

1、IO

       IO (Input/Output,輸入/輸出)即資料的讀取(接收)或寫入(傳送)操作,通常使用者程序中的一個完整IO分為兩階段:使用者程序空間<-->核心空間、核心空間<-->裝置空間(磁碟、網路等)IO有記憶體IO、網路IO和磁碟IO三種,通常我們說的IO指的是後兩者。

       LINUX中程序無法直接操作I/O裝置,其必須通過系統呼叫請求kernel來協助完成I/O動作;核心會為每個I/O裝置維護一個緩衝區。

       對於一個輸入操作來說,程序IO系統呼叫後,核心會先看緩衝區中有沒有相應的快取資料,沒有的話再到裝置中讀取,因為裝置IO一般速度較慢,需要等待;核心緩衝區有資料則直接複製到程序空間。

       所以,對於一個網路輸入操作通常包括兩個不同階段:

(1)等待網路資料到達網絡卡→讀取到核心緩衝區,資料準備好;

(2)從核心緩衝區複製資料到程序空間。

2、5種IO模型

       《UNIX網路程式設計》說得很清楚,5種IO模型分別是阻塞IO模型、非阻塞IO模型、IO複用模型、訊號驅動的IO模型、非同步IO模型;前4種為同步IO操作,只有非同步IO模型是非同步IO操作。下面這樣些圖,是它裡面給出的例子:接收網路UDP資料的流程在IO模型下的分析,在它的基礎上再加以簡單描述,以區分這些IO模型。

2-1、阻塞IO模型

       程序發起IO系統呼叫後,程序被阻塞,轉到核心空間處理,整個IO處理完畢後返回程序。操作成功則程序獲取到資料。

1、典型應用:阻塞socket、Java BIO;

2、特點:

程序阻塞掛起不消耗CPU資源,及時響應每個操作

實現難度低、開發應用較容易;

適用併發量小的網路應用開發;

不適用併發量大的應用:因為一個請求IO會阻塞程序,所以,得為每請求分配一個處理程序(執行緒)以及時響應,系統開銷大。

2-2、非阻塞IO模型

       程序發起IO系統呼叫後,如果核心緩衝區沒有資料,需要到IO裝置中讀取,程序返回一個錯誤而不會被阻塞;程序發起IO系統呼叫後,如果核心緩衝區有資料,核心就會把資料返回程序。

       對於上面的阻塞IO模型來說,核心資料沒準備好需要程序阻塞的時候,就返回一個錯誤,以使得程序不被阻塞。

1、典型應用:socket是非阻塞的方式(設定為NONBLOCK)

2、特點:

程序輪詢(重複)呼叫,消耗CPU的資源

實現難度低、開發應用相對阻塞IO模式較難;

 適用併發量較小、且不需要及時響應的網路應用開發;

2-3、IO複用模型

       多個的程序的IO可以註冊到一個複用器(select)上,然後用一個程序呼叫該select, select會監聽所有註冊進來的IO;

       如果select沒有監聽的IO在核心緩衝區都沒有可讀資料,select呼叫程序會被阻塞;而當任一IO在核心緩衝區中有可資料時,select呼叫就會返回;

       而後select呼叫程序可以自己或通知另外的程序(註冊程序)來再次發起讀取IO,讀取核心中準備好的資料。

       可以看到,多個程序註冊IO後,只有另一個select呼叫程序被阻塞。

1、典型應用:select、poll、epoll三種方案,nginx都可以選擇使用這三個方案;Java NIO;

2、特點:

專一程序解決多個程序IO的阻塞問題,效能好Reactor模式;

實現、開發應用難度較大;

適用高併發服務應用開發:一個程序(執行緒)響應多個請求

3、select、poll、epoll

Linux中IO複用的實現方式主要有select、poll和epoll:

Select:註冊IO、阻塞掃描,監聽的IO最大連線數不能多於FD_SIZE;

Poll:原理和Select相似,沒有數量限制,但IO數量大掃描線性效能下降;

Epoll :事件驅動不阻塞,mmap實現核心與使用者空間的訊息傳遞,數量很大,Linux2.6後核心支援;

 2-4、訊號驅動IO模型

       當程序發起一個IO操作,會向核心註冊一個訊號處理函式,然後程序返回不阻塞;當核心資料就緒時會發送一個訊號給程序,程序便在訊號處理函式中呼叫IO讀取資料。

       1、特點:回撥機制,實現、開發應用難度大;

2-5、非同步IO模型

       當程序發起一個IO操作,程序返回(不阻塞),但也不能返回果結;核心把整個IO處理完後,會通知程序結果。如果IO操作成功則程序直接獲取到資料

1、典型應用:JAVA7 AIO、高效能伺服器應用

2、特點:

不阻塞,資料一步到位Proactor模式

需要作業系統的底層支援,LINUX 2.5 版本核心首現,2.6 版本產品的核心標準特性;

實現、開發應用難度大;

非常適合高效能高併發應用;

3、IO模型比較

3-1、阻塞IO呼叫和非阻塞IO呼叫、阻塞IO模型和非阻塞IO模型

       注意這裡的阻塞IO呼叫和非阻塞IO呼叫不是指阻塞IO模型和非阻塞IO模型:

阻塞IO呼叫 :在使用者程序(執行緒)中呼叫執行的時候,程序會等待該IO操作,而使得其他操作無法執行。

非阻塞IO呼叫:在使用者程序中呼叫執行的時候,無論成功與否,該IO操作會立即返回,之後程序可以進行其他操作(當然如果是讀取到資料,一般就接著進行資料處理)。

       這個直接理解就好,程序(執行緒)IO呼叫會不會阻塞程序自己。所以這裡兩個概念是相對呼叫程序本身狀態來講的。

       從上面對比圖片來說,阻塞IO模型是一個阻塞IO呼叫,而非阻塞IO模型是多個非阻塞IO呼叫+一個阻塞IO呼叫,因為多個IO檢查會立即返回錯誤,不會阻塞程序。

       而上面也說過了,非阻塞IO模型對於阻塞IO模型來說區別就是,核心資料沒準備好需要程序阻塞的時候,就返回一個錯誤,以使得程序不被阻塞。

3-2、同步IO和非同步IO

同步IO:導致請求程序阻塞,直到I/O操作完成。

非同步IO:不導致請求程序阻塞。

       上面兩個定義是《UNIX網路程式設計 卷1:套接字聯網API》給出的。這不是很好理解,我們來擴充套件一下,先說說同步和非同步,同步和非同步關注的是雙方的訊息通訊機制

同步:雙方的動作是經過雙方協調的,步調一致的。

非同步:雙方並不需要協調,都可以隨意進行各自的操作。

       這裡我們的雙方是指,使用者程序和IO裝置;明確同步和非同步之後,我們在上面網路輸入操作例子的基礎上,進行擴充套件定義:

同步IO使用者程序發出IO呼叫,去獲取IO裝置資料,雙方的資料要經過核心緩衝區同步,完全準備好後,再複製返回到使用者程序。而複製返回到使用者程序會導致請求程序阻塞,直到I/O操作完成。

非同步IO使用者程序發出IO呼叫,去獲取IO裝置資料,並不需要同步,核心直接複製到程序,整個過程不導致請求程序阻塞。

      所以, 阻塞IO模型、非阻塞IO模型、IO複用模型、訊號驅動的IO模型者為同步IO模型,只有非同步IO模型是非同步IO。