1. 程式人生 > >常見的網絡 I/O 模型

常見的網絡 I/O 模型

性能 tail clas 處理程序 系統 只需要 同步 來源 io復用

基礎概念

同步、異步、阻塞、非阻塞

同步 & 異步

同步與異步是針對多個事件(線程/進程)來說的。

  • 如果事件A需要等待事件B的完成才能完成,這種串行執行機制可以說是同步的,這是一種可靠的任務序列,要麽都成功,要麽都失敗。
  • 如果事件B的執行不需要依賴事件A的完成結果,這種並行的執行機制可以說是異步的。事件B不確定事件A是否真正完成,所以是不可靠的任務序列。

同步異步可以理解為多個事件的執行方式和執行時機如何,是串行等待還是並行執行。同步中依賴事件等待被依賴事件的完成,然後觸發自身開始執行,異步
中依賴事件不需要等待被依賴事件,可以和被依賴事件並行執行,被依賴事件執行完成後,可以通過回調、通知等方式告知依賴事件。

阻塞 & 非阻塞

阻塞與非阻塞是針對單一事件(線程/進程)來說的。

  • 對於阻塞,如果一個事件在發起一個調用之後,在調用結果返回之前,該事件會被一直掛起,處於等待狀態。
  • 對於非阻塞,如果一個事件在發起調用以後,無論該調用當前是否得到結果,都會立刻返回,不會阻塞當前事件。

阻塞與非阻塞可以理解為單個事件在發起其他調用以後,自身的狀態如何,是苦苦等待還是繼續幹自己的事情。非阻塞雖然能提高CPU利用率,但是也帶來了系統線程切換的成本,需要在CPU執行時間和系統切換成本之間好好估量一下。

同步阻塞

應用程序執行系統調用,應用程序會一直阻塞,直到系統調用完成。應用程序處於不再消費CPU而只是簡單等待響應的狀態。當響應返回時,數據被移動到用戶空間的緩沖區,應用程序解除阻塞。

技術分享圖片

同步阻塞I/O模型.

同步非阻塞

設備以非阻塞形式打開,I/O操作不會立即完成,read操作可能會返回一個錯誤代碼。應用程序可以執行其他操作,但需要請求多次I/O操作,直到數據可用。

技術分享圖片技術分享圖片

同步非阻塞形式實際上是效率低下的,因為:

  • 應用程序需要在不同的任務之間切換。異步非阻塞是你只需要執行當前任務,系統調用會主動通知你,不用頻繁切換。
  • 數據在內核中變為可用到調用read返回數據之間存在時間間隔,會造成整體數據吞吐量降低

異步非阻塞

應用程序的其他處理任務與I/O任務重疊進行。讀請求會立即返回,說明請求已經成功發起,應用程序不被阻塞,繼續執行其它處理操作。當read響應到達,將數據拷貝到用戶空間,產生信號或者執行一個基於線程回調函數完成I/O處理。應用程序不用在多個任務之間切換。

技術分享圖片

非阻塞I/O和異步I/O區別在於,在非阻塞I/O中,雖然進程大部分時間不會被block,但是需要不停的去主動check,並且當數據準備完成以後,也需要應用程序主動調用recvfrom將數據拷貝到用戶空間;異步I/O則不同,就像是應用程序將整個I/O操作交給了內核完成,然後由內核發信號通知。期間應用程序不需要主動去檢查I/O操作狀態,也不需要主動從內核空間拷貝數據到用戶空間。

非阻塞I/O看起來是non-blocking的,但是只是在內核數據沒準備好時,當數據準備完成,recvfrom需要從內核空間拷貝到用戶空間,這個時候其實是被block住的。而異步I/O是當進程發起I/O操作後,再不用主動去請求,知道內核數據準備好並發出信號通知,整個過程完全沒有block。


文件描述符(基礎概念補充)

文件描述符用於表示指向文件引用的抽象畫概念。在形式上是一個非負整數,實際上是一個索引值,指向內核為每一個進程維護的該進程打開文件的記錄表。當程序打開一個現有文件或者創建一個新文件時,內核向進程返回個文件描述符。

Linux 系統中,包括文件、設備在內的許多事物的操作都被當成文件來操作,當 Linux 系統對文件操作時都會調用操作系統的系統調用,然後該系統調用返回一個文件描述符。在 Linux 系統中對網絡 I/O 的操作同樣也會返回相應的 Socket 文件描述符。

Linux 操作系統總共有 5 種網絡 I/O 模型

l 阻塞I/O

l 非阻塞I/O

l I/O復用(select、poll、linux 2.6種改進的epoll)

l 信號驅動IO(SIGIO)

l 異步I/O(POSIX的aio_系列函數)

阻塞 I/O 模型

阻塞 I/O 模型是在操作系統發起系統調用調用之後,要等到操作系統系統內核所有的 I/O 操作完成才返回。阻塞 I/O 模型的內核態調用過程如下:首先操作系統內核調用 recvfrom()方法,調用之後進程進入阻塞狀態,等待數據包達到。如果數據包到達或者在執行過程中出現 I/O 等方面的錯誤時才會調用完成,代碼返回。阻塞 I/O 模型的特征主要是:當調用者使用阻塞 I/O 系統調用時,在 I/O 操作在內核態完成所有操作前,調用者會一直在這個點等待等待,處於阻塞狀態;只有在操作系統內核完成了相應的操作之後函數才返回,調用者才能繼續執行下面的代碼。

技術分享圖片

非阻塞 I/O 模型是:進程使用非阻塞 I/O 系統調用時,如果系統由於繁忙等原因不能立即返回相應操作的結果,則該 I/O 函數會置相應的錯誤號並且立即返回,而不是和阻塞 I/O 操作一樣,等待數據到來。非阻塞 I/O 模型的內核態調用過程如下:當調用 recvfrom()方法時,內核馬上給該系統調用返回錯誤碼。當再次調用recvfrom()方法時,如果操作系統的數據已經就緒,則會將數據復制到緩存區等待讀取,同時 recvfrom()方法返回成功。如果操作系統的數據沒有準備好,則繼續返回錯誤碼

I/O 復用模型

I/O 復用模型中,系統會首先構造一張有關文件或者 Socket 描述符的列表,然後調用一個特定的函數,當至少有一個描述符準備好進行 I/O 操作時,函數才會返回結果。此時進程就能夠獲取到可進行 I/O 操作的描述符集合。Linux 提供了select()/poll()接口來執行多路復用的功能

然而,select/poll 依次掃描文件描述符,依次判斷文件描述符是否就緒。但是由於 select/poll 所能使用的文件描述符數量有限,因此它在實際使用過程中會有些限制。為了解決 select/poll 順序掃描效率低下的問題,Linux 系統還有一種基於事件驅動方式的系統調用 epoll。由於 epoll 根據事件來查詢文件描述符,因此性能會高很多。當有文件描述符的狀態就緒時,模型馬上執行之前傳入的回調函數。

技術分享圖片

多路復用的本質是同步非阻塞I/O,多路復用的優勢並不是單個連接處理的更快,而是在於能處理更多的連接。

I/O編程過程中,需要同時處理多個客戶端接入請求時,可以利用多線程或者I/O多路復用技術進行處理。
I/O多路復用技術通過把多個I/O的阻塞復用到同一個select阻塞上,一個進程監視多個描述符,一旦某個描述符就位, 能夠通知程序進行讀寫操作。因為多路復用本質上是同步I/O,都需要應用程序在讀寫事件就緒後自己負責讀寫。
最大的優勢是系統開銷小,不需要創建和維護額外線程或進程。

  • 應用場景
    • 服務器需要同時處理多個處於監聽狀態或者多個連接狀態的套接字
    • 需要同時處理多種網絡協議的套接字
    • 一個服務器處理多個服務或協議

目前支持多路復用的系統調用有select, poll, epoll。

信號驅動 I/O 模型

在信號驅動的 I/O 模型中,實現了真正意義上的異步形式的通知,通過信號機制來獲取描述符的狀態信息。首先在等待的描述符上註冊回調函數,當事件發生後,回調函數負責將描述符狀態寫入用戶空間並通知相關進程,對於某個描述符,

發生了所關心的事件。之後就可以在處理程序中調用 recvfrom()方法來讀數據

技術分享圖片

異步 I/O

這種模型是真正意義上的異步。應用進程發起一個系統調用後,會馬上返回,可以執行其他的操作。 但該調用會讓內核觸發一個操作,完成數據從內核拷貝到用戶自己的緩沖區,操作完成後,內核會通知進程,然後進程對放在緩沖區的數據再進行處理。如圖

技術分享圖片

同步IO和異步IO

  • 同步IO操作導致請求進程阻塞,直到IO操作完成
  • 異步IO操作不導致請求進行阻塞

從理論上講,非阻塞IO、阻塞IO、IO復用和信號驅動IO都是同步IO模型。因為這四種IO模型中,IO的讀寫操作,都是在IO事件發生之後,由應用進程來完成的。而POSIX規範所定義的異步IO模型則不同。對異步IO而言,用戶可以直接對IO執行讀寫操作,這些操作告訴內核用戶讀寫緩沖區的位置,以及IO操作完成之後內核通知應用程序的方式。異步IO的讀寫操作總是立即返回,而不論IO是否是阻塞的,因為真正的讀寫操作已經由內核接管。也就是說,同步IO模型要求用戶代碼自行執行IO操作(將數據從內核緩沖區讀入用戶緩沖區,或將數據從用戶緩沖區寫入內核緩沖區),而異步IO機制則由內核來執行IO操作(數據在內核緩沖區和用戶緩沖區之間的移動是由內核在“後臺”完成的)。你可以這樣認為,同步IO向應用程序通知的是IO就緒事件,而異步IO向應用程序通知的是IO完成事件。

資料來源:https://www.cnblogs.com/wuchanming/p/4442146.html作者:Jessica程序猿
鏈接:https://www.jianshu.com/p/439e8b349f48

作者:rainybowe
來源:簡書
https://blog.csdn.net/moakun/article/details/81042877作者:茅坤寶駿氹

論文:基於Netty的高可服務消息中間件的研究與實現_崔曉旻

基於Netty的消息中間件的研究與實現_夏斐

常見的網絡 I/O 模型