深入理解JAVA I/O系列六:Linux中的IO模型

來源:互聯網
上載者:User

標籤:

IO模型

  linux系統IO分為核心準備資料和將資料從核心拷貝到使用者空間兩個階段。

 

這張圖大致描述了資料從外部磁碟向運行中程式的記憶體中移動的過程。

使用者空間、核心空間

  現在作業系統都是採用虛擬儲存空間,那麼對32位作業系統而言,它的定址空間(虛擬儲存空間)為4G(2的32次方)。作業系統的核心是核心,獨立於普通的應用程式,可以訪問受保護的記憶體空間,也有訪問底層硬體裝置的所有許可權。為了保證使用者進程不能直接操作核心,保證核心的安全,作業系統將虛擬空間劃分為兩個部分,一個部分為核心空間,一部分為使用者空間。

  如何分配這兩個空間的大小也是有講究的,如windows 32位作業系統,預設的使用者空間:核心空間的比例是1:1;而在32位Linux系統中的預設比例是3:1(3G使用者空間,1G核心空間)。

進程切換

  為了控制進程的執行,核心必須要有能力掛起正在CPU上啟動並執行進程,並恢複以前掛起的某個進程的執行。這種行為成為進程的切換。任何進程都是在作業系統核心的支援下啟動並執行,是與核心緊密相關的。

進程切換的過程,會經過下面這些變化:

1、儲存處理機上下文,包括程式計數器和其他寄存器。

2、更新PCB資訊。

3、將進程的PCB移入相應的隊列,如就緒、在某事件阻塞等隊列。

4、選擇另外一個進程執行,並更新PCB

5、更新記憶體管理的資料結構。

6、恢複處理機上下文

緩衝IO

  緩衝IO又稱稱為標準IO,大多數檔案系統的預設IO操作都是緩衝IO。在Linux的緩衝IO機制中,作業系統會將IO的資料緩衝在檔案系統的頁緩衝(page cache)。也就是說,資料會先被拷貝到作業系統核心的緩衝區中,然後才會從作業系統核心的緩衝區拷貝到應用程式的地址空間中。

  這種做法的缺點就是,需要在應用程式地址空間和核心進行多次拷貝,這些拷貝動作所帶來的CPU以及記憶體開銷是非常大的。

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

 1、IO同步調用要求主線程等待IO線程返回,非同步呼叫只是啟動IO線程並立即返回,在IO完成後通過回呼函數等通知機制通知主線程。同步非同步區別在於資料拷貝過程中主線程        是否阻塞。

2、阻塞IO在返回前主線程被掛起,非阻塞IO則不掛起主線程,從調用者角度來看,阻塞與非阻塞IO的區別也可以理解為調用     是否立即返回。

3、由此可見,同步非同步與阻塞非阻塞IO是不同標準下的分類。阻塞非阻塞IO關注的是程式在等待調用結果是的一個狀態。

Linux IO模型

  網路IO的本質就是socket的讀取,socket在linux系統被抽象為流,IO可以理解為對流的操作。文章開始的時候也提到了,對於一次IO訪問(以read為例),資料會先被拷貝到作業系統核心的緩衝區,然後才會從作業系統核心的緩衝區拷貝到應用程式的地址空間中。所以說,當一個read操作發生時,它會經曆兩個階段:

第一個階段:等待資料準備。

第二個階段:將資料從核心拷貝到進程中

對於socket流而言:

第一步:通常涉及等待網路上的資料分組到達,然後複製到核心的某個緩衝區。

第二步:把資料從核心緩衝區複製到應用進程緩衝區。

當然,如果核心空間的緩衝區中已經有資料了,那麼就可以省略第一步。至於為什麼不能直接讓磁碟控制卡把資料送到應用程式的地址空間中呢?最簡單的一個原因就是應用程式不能直接操作底層硬體。

網路應用需要處理的無非就是兩大類問題,網路IO,資料計算。相對於後者,網路IO的延遲,給應用帶來的效能瓶頸大於後者。網路IO的模型大致分為如下五種:

1、阻塞IO

2、非阻塞IO

3、多工IO

4、訊號驅動IO

5、非同步IO

前四種都是同步,只有最後一種是非同步IO。下面的模型介紹先以生活中的例子來說明概念:周末和女友去商場逛街,到了晚上飯點,準備吃完飯再去逛街,但是周末人多,新白鹿飯店需要排隊,於是有如下幾種方案可供選擇:

1、阻塞IO模型

情境描述:

  在飯店領完號後,前面還有n桌,不知道什麼時候到我們,但是又不能離開,因為過號之後必須重新取號。只好在飯店裡等,一直等到叫號到我們才吃完晚飯,然後去逛街。中間等待的時間什麼事情都不能做。

網路模型:

  在這個模型中,應用程式為了執行這個read操作,會調用相應的一個system call,將系統控制權交給核心,然後就進行等待(這個等待的過程就是被阻塞了),核心開始執行這個system call,執行完畢後會嚮應用程式返迴響應,應用程式得到響應後,就不再阻塞,並進行後面的工作。

優點:

  能夠及時返回資料,無延遲。

缺點:

  對使用者來說處於等待就要付出效能代價。

2、非阻塞IO

情境描述:

  等待過程是在太無聊,於是我們就去逛商場,每隔一段時間就回來詢問服務員,叫號是否到我們了,整個過程來來回回好多次。這就是非阻塞,但是需要不斷的詢問。

網路模型:

  當使用者進程發出read操作時,調用相應的system call,這個system call會立即從核心中返回。但是在返回的這個時間點,核心中的資料可能還沒有準備好,也就是說核心只是很快就返回了system call,只有這樣才不會阻塞使用者進程,對於應用程式,雖然這個IO操作很快就返回了,但是它並不知道這個IO操作是否真的成功了,為了知道IO操作是否成功,應用程式需要主動的迴圈去問核心。

優點:

  能夠在等待的時間裡去做其他的事情。

缺點:

  任務完成的響應延遲增大了,因為每過一段時間去輪詢一次read操作,而任務可能在兩次輪詢之間的任意時間完成,這對導致整體資料輸送量的降低。

3、IO多工

情境描述:

  與第二個經常類似,飯店安裝了電子螢幕,顯示叫號的狀態,所以在逛街的時候,就不用去詢問服務員,而是看下大螢幕就可以了。(不僅僅是我們不用詢問服務員,其他所有的人都可以不用詢問服務員)

網路模型:

  和第二種一樣,調用system call之後,並不等待核心的返回結果而是立即返回。雖然返回結果的調用函數是一個非同步方式,但應用程式會被像select、poll和epoll等具有多個檔案描述符的函數阻塞住,一直等到這個system call有結果返回了,再通知應用程式。這種情況,從IO操作的實際效果來看,非同步阻塞IO和第一種同步阻塞IO是一樣的,應用程式都是一直等到IO操作成功之後(資料已經被寫入或者讀取),才開始進行下面的工作。不同點在於非同步阻塞IO用一個select函數可以為多個檔案描述符提供通知,提供了並發性。舉個例子:例如有一萬個並發的read請求,但是網路上仍然沒有資料,此時這一萬個read會同時各自阻塞,現在用select、poll、epoll這樣的函數來專門負責阻塞同時監聽這一萬個請求的狀態,一旦有資料到達了就負責通知,這樣就將一萬個等待和阻塞轉化為一個專門的函數來負責與管理。

  非同步阻塞IO與同步非阻塞IO的區別在於:同步非阻塞IO是需要應用程式主動地迴圈去詢問是否有資料,而非同步阻塞IO是通過像select等IO多工函數來同時檢測多個事件控制代碼來告知應用程式是否有資料。

  瞭解了前面三種IO模式,在使用者進程進行系統調用的時候,他們在等待資料到來的時候,處理的方式是不一樣的,直接等待、輪詢、select或poll輪詢,兩個階段過程:

第一個階段有的阻塞,有的不阻塞,有的可以阻塞又可以不阻塞。

第二個階段都是阻塞的。

從整個IO過程來看,他們都是順序執行的,因此可以歸為同步模型,都是進程自動等待且向核心檢查狀態。

  高並發的程式一般使用同步非阻塞模式,而不是多線程+同步阻塞模式。要理解這點,先弄明白並發和並行的區別:比如去某部門辦事需要依次去幾個視窗,辦事大廳的人數就是並發數,而視窗的個數就是並行度。就是說並發是同時進行的任務數(如同時服務的http請求),而並行數就是可以同時工作的實體資源數量(如cpu核心數)。通過合理調度任務的不同階段,並發數可以遠遠大於並行度。這就是區區幾個CPU可以支撐上萬個使用者並發請求的原因。在這種高並發的情況下,為每個使用者請求建立一個進程或者線程的開銷非常大。而同步非阻塞方式可以把多個IO請求丟到後台去,這樣一個CPU就可以服務大量的並發IO請求。

  IO多工究竟是同步阻塞還是非同步阻塞模型,這裡來展開說說:

  同步是需要主動等待訊息通知,而非同步則是被動接受訊息通知,通過回調、通知、狀態等方式來被動擷取訊息。IO多工在阻塞到select階段時,使用者進程是主動等待並調用select函數來擷取就緒狀態訊息,並且其進程狀態為阻塞。所以IO多工是同步阻塞模式。

4、訊號驅動式IO

  應用程式提交read請求,調用system call,然後核心開始處理相應的IO操作,而同時,應用程式並不等核心返迴響應,就會開始執行其他的處理操作(應用程式沒有被IO阻塞),當核心執行完畢,返回read響應,就會產生一個訊號或執行一個基於線程的回呼函數來完成這次IO處理過程。在這裡IO的讀寫操作是在IO事件發生之後由應用程式來完成。非同步IO讀寫操作總是立即返回,而不論IO是否阻塞,因為真正的讀寫操作已經有核心掌管。也就是說同步IO模型要求使用者代碼自行執行IO操作(將資料從核心緩衝區移動使用者緩衝區或者相反),而非同步作業機制則是由核心來執行IO操作(將資料從核心緩衝區移動使用者緩衝區或者相反)。可以這樣認為,同步IO嚮應用程式通知的是IO就緒事件,而非同步IO嚮應用程式通知的是IO完成事件。

5、非同步IO

  非同步IO與上面的非同步概念是一樣的, 當一個非同步程序呼叫發出後,調用者不能立刻得到結果,實際處理這個調用的函數在完成後,通過狀態、通知和回調來通知調用者的輸入輸出操作。非同步IO的工作機制是:告知核心啟動某個操作,並讓核心在整個操作完成後通知我們,這種模型與訊號驅動的IO區別在於,訊號驅動IO是由核心通知我們何時可以啟動一個IO操作,這個IO操作由使用者自訂的訊號函數來實現,而非同步IO模型是由核心告知我們IO操作何時完成。

 

深入理解JAVA I/O系列六:Linux中的IO模型

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.