溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解Linux操作系統(tǒng) IO 模式

發(fā)布時間:2021-11-02 09:21:07 來源:億速云 閱讀:141 作者:柒染 欄目:系統(tǒng)運維

這期內(nèi)容當中小編將會給大家?guī)碛嘘P如何理解Linux操作系統(tǒng) IO 模式,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

 IO

如何理解Linux操作系統(tǒng) IO 模式

IO  (Input/Output,輸入/輸出)即數(shù)據(jù)的讀取(接收)或?qū)懭?發(fā)送)操作,通常用戶進程中的一個完整IO分為兩階段:用戶進程空間<-->內(nèi)核空間、內(nèi)核空間<-->設備空間(磁盤、網(wǎng)絡等)。IO有內(nèi)存IO、網(wǎng)絡IO和磁盤IO三種,通常我們說的IO指的是后兩者。

LINUX中進程無法直接操作I/O設備,其必須通過系統(tǒng)調(diào)用請求kernel來協(xié)助完成I/O動作;內(nèi)核會為每個I/O設備維護一個緩沖區(qū)。

對于一個輸入操作來說,進程IO系統(tǒng)調(diào)用后,內(nèi)核會先看緩沖區(qū)中有沒有相應的緩存數(shù)據(jù),沒有的話再到設備中讀取,因為設備IO一般速度較慢,需要等待;內(nèi)核緩沖區(qū)有數(shù)據(jù)則直接復制到進程空間。

所以,對于一個網(wǎng)絡輸入操作通常包括兩個不同階段:

(1)等待網(wǎng)絡數(shù)據(jù)到達網(wǎng)卡&rarr;讀取到內(nèi)核緩沖區(qū),數(shù)據(jù)準備好;

(2)從內(nèi)核緩沖區(qū)復制數(shù)據(jù)到進程空間。

關鍵概念理解

  • 同步:發(fā)起一個調(diào)用,得到結(jié)果才返回。

  • 異步:調(diào)用發(fā)起后,調(diào)用直接返回;調(diào)用方主動詢問被調(diào)用方獲取結(jié)果,或被調(diào)用方通過回調(diào)函數(shù)。

  • 阻塞:調(diào)用是指調(diào)用結(jié)果返回之前,當前線程會被掛起。調(diào)用線程只有在得到結(jié)果之后才會返回。

  • 非阻塞:調(diào)用指在不能立刻得到結(jié)果之前,該調(diào)用不會阻塞當前線程。

同步才有阻塞和非阻塞之分;

阻塞與非阻塞關乎如何對待事情產(chǎn)生的結(jié)果(阻塞:不等到想要的結(jié)果我就不走了)

明確進程狀態(tài)

理解進程的狀態(tài)轉(zhuǎn)換

  • 就緒狀態(tài) -> 運行狀態(tài):處于就緒狀態(tài)的進程被調(diào)度后,獲得CPU資源(分派CPU時間片),于是進程由就緒狀態(tài)轉(zhuǎn)換為運行狀態(tài)。

  • 運行狀態(tài) ->  就緒狀態(tài):處于運行狀態(tài)的進程在時間片用完后,不得不讓出CPU,從而進程由運行狀態(tài)轉(zhuǎn)換為就緒狀態(tài)。此外,在可剝奪的操作系統(tǒng)中,當有更高優(yōu)先級的進程就 、  緒時,調(diào)度程度將正執(zhí)行的進程轉(zhuǎn)換為就緒狀態(tài),讓更高優(yōu)先級的進程執(zhí)行。

  • 運行狀態(tài) ->  阻塞狀態(tài):當進程請求某一資源(如外設)的使用和分配或等待某一事件的發(fā)生(如I/O操作的完成)時,它就從運行狀態(tài)轉(zhuǎn)換為阻塞狀態(tài)。進程以系統(tǒng)調(diào)用的形式請求操作系統(tǒng)提供服務,這是一種特殊的、由運行用戶態(tài)程序調(diào)用操作系統(tǒng)內(nèi)核過程的形式。

  • 阻塞狀態(tài) -> 就緒狀態(tài):當進程等待的事件到來時,如I/O操作結(jié)束或中斷結(jié)束時,中斷處理程序必須把相應進程的狀態(tài)由阻塞狀態(tài)轉(zhuǎn)換為就緒狀態(tài)。

如何理解Linux操作系統(tǒng) IO 模式

從操作系統(tǒng)層面執(zhí)行應用程序理解 IO 模型

阻塞IO模型:

  • 簡介:進程會一直阻塞,直到數(shù)據(jù)拷貝完成應用程序調(diào)用一個IO函數(shù),導致應用程序阻塞,等待數(shù)據(jù)準備好。  如果數(shù)據(jù)沒有準備好,一直等待&hellip;.數(shù)據(jù)準備好了,從內(nèi)核拷貝到用戶空間,IO函數(shù)返回成功指示。 我們 第一次接觸到的網(wǎng)絡編程都是從  listen()、send()、recv()等接口開始的。使用這些接口可以很方便的構(gòu)建服務器 /客戶機的模型。

  • 阻塞I/O模型圖:在調(diào)用recv()/recvfrom()函數(shù)時,發(fā)生在內(nèi)核中等待數(shù)據(jù)和復制數(shù)據(jù)的過程。

如何理解Linux操作系統(tǒng) IO 模式

當調(diào)用recv()函數(shù)時,系統(tǒng)首先查是否有準備好的數(shù)據(jù)。如果數(shù)據(jù)沒有準備好,那么系統(tǒng)就處于等待狀態(tài)。當數(shù)據(jù)準備好后,將數(shù)據(jù)從系統(tǒng)緩沖區(qū)復制到用戶空間,然后該函數(shù)返回。在套接應用程序中,當調(diào)用recv()函數(shù)時,未必用戶空間就已經(jīng)存在數(shù)據(jù),那么此時recv()函數(shù)就會處于等待狀態(tài)。

阻塞模式給網(wǎng)絡編程帶來了一個很大的問題,如在調(diào)用  send()的同時,線程將被阻塞,在此期間,線程將無法執(zhí)行任何運算或響應任何的網(wǎng)絡請求。這給多客戶機、多業(yè)務邏輯的網(wǎng)絡編程帶來了挑戰(zhàn)。這時,我們可能會選擇多線程的方式來解決這個問題。

應對多客戶機的網(wǎng)絡應用,最簡單的解決方式是在服務器端使用多線程(或多進程)。多線程(或多進程)的目的是讓每個連接都擁有獨立的線程(或進程),這樣任何一個連接的阻塞都不會影響其他的連接。

具體使用多進程還是多線程,并沒有一個特定的模式。傳統(tǒng)意義上,進程的開銷要遠遠大于線程,所以,如果需要同時為較多的客戶機提供服務,則不推薦使用多進程;如果單個服務執(zhí)行體需要消耗較多的  CPU 資源,譬如需要進行大規(guī)模或長時間的數(shù)據(jù)運算或文件訪問,則進程較為安全。

非阻塞IO模型

  • 簡介:非阻塞IO通過進程反復調(diào)用IO函數(shù)(多次系統(tǒng)調(diào)用,并馬上返回);在數(shù)據(jù)拷貝的過程中,進程是阻塞的;  我們把一個SOCKET接口設置為非阻塞就是告訴內(nèi)核,當所請求的I/O操作無法完成時,不要將進程睡眠,而是返回一個錯誤。這樣我們的I/O操作函數(shù)將不斷的測試數(shù)據(jù)是否已經(jīng)準備好,如果沒有準備好,繼續(xù)測試,直到數(shù)據(jù)準備好為止。在這個不斷測試的過程中,會大量的占用CPU的時間。

如何理解Linux操作系統(tǒng) IO 模式

IO復用模型:

  • 簡介:IO multiplexing就是我們說的select,poll,epoll,有些地方也稱這種IO方式為event driven  IO。select/epoll的好處就在于單個process就可以同時處理多個網(wǎng)絡連接的  IO。它的基本原理就是select,poll,epoll這個function會不斷的輪詢所負責的所有socket,當某個socket有數(shù)據(jù)到達了,就通知用戶進程。

如何理解Linux操作系統(tǒng) IO 模式

當用戶進程調(diào)用了select,那么整個進程會被block,而同時,kernel會“監(jiān)視”所有select負責的socket,當任何一個socket中的數(shù)據(jù)準備好了,select就會返回。這個時候用戶進程再調(diào)用read操作,將數(shù)據(jù)從kernel拷貝到用戶進程。

所以,I/O  多路復用的特點是通過一種機制一個進程能同時等待多個文件描述符,而這些文件描述符(套接字描述符)其中的任意一個進入讀就緒狀態(tài),select()函數(shù)就可以返回。

異步IO模型

  • 簡介:用戶進程發(fā)起read操作之后,立刻就可以開始去做其它的事。而另一方面,從kernel的角度,當它受到一個asynchronous  read之后,首先它會立刻返回,所以不會對用戶進程產(chǎn)生任何block。然后,kernel會等待數(shù)據(jù)準備完成,然后將數(shù)據(jù)拷貝到用戶內(nèi)存,當這一切都完成之后,kernel會給用戶進程發(fā)送一個signal,告訴它read操作完成了。

如何理解Linux操作系統(tǒng) IO 模式

區(qū)別IO多路復用中的select poll epoll

select

int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,  struct timeval *timeout); select  函數(shù)監(jiān)視的文件描述符分3類,分別是writefds、readfds、和exceptfds。調(diào)用后select函數(shù)會阻塞,直到有描述符就緒(有數(shù)據(jù)  可讀、可寫、或者有except),或者超時(timeout指定等待時間,如果立即返回設為null即可),函數(shù)返回。當select函數(shù)返回后,可以  通過遍歷fdset,來找到就緒的描述符

poll

int poll (struct pollfd *fds, unsigned int nfds, int timeout);  不同與select使用三個位圖來表示三個fdset的方式,poll使用一個  pollfd的指針實現(xiàn)。pollfd并沒有最大數(shù)量限制(但是數(shù)量過大后性能也是會下降)。  和select函數(shù)一樣,poll返回后,需要輪詢pollfd來獲取就緒的描述符。

epoll

epoll是通過事件的就緒通知方式,調(diào)用epoll_create創(chuàng)建實例,調(diào)用epoll_ctl添加或刪除監(jiān)控的文件描述符,調(diào)用epoll_wait阻塞住,直到有就緒的文件描述符,通過epoll_event參數(shù)返回就緒狀態(tài)的文件描述符和事件。

epoll操作過程需要三個接口,分別如下: int epoll_create(int  size);//創(chuàng)建一個epoll的句柄,size用來告訴內(nèi)核這個監(jiān)聽的數(shù)目一共有多大 生成一個 epoll  專用的文件描述符,其實是申請一個內(nèi)核空間,用來存放想關注的 socket fd 上是否發(fā)生以及發(fā)生了什么事件。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

控制某個 epoll 文件描述符上的事件:注冊、修改、刪除。其中參數(shù) epfd 是 epoll_create() 創(chuàng)建 epoll  專用的文件描述符。

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int  timeout);

等待 I/O 事件的發(fā)生;返回發(fā)生事件數(shù)。參數(shù)說明:

epfd: 由 epoll_create() 生成的 Epoll 專用的文件描述符;

epoll_event: 用于回傳代處理事件的數(shù)組;

maxevents: 每次能處理的事件數(shù);

timeout: 等待 I/O 事件發(fā)生的超時值;

區(qū)別總結(jié)

(1)select,poll實現(xiàn)需要自己不斷輪詢所有fd集合,直到設備就緒,期間可能要睡眠和喚醒多次交替。而epoll其實也需要調(diào)用epoll_wait不斷輪詢就緒鏈表,期間也可能多次睡眠和喚醒交替,但是它是設備就緒時,調(diào)用回調(diào)函數(shù),把就緒fd放入就緒鏈表中,并喚醒在epoll_wait中進入睡眠的進程。雖然都要睡眠和交替,但是select和poll在“醒著”的時候要遍歷整個fd集合,而epoll在“醒著”的時候只要判斷一下就緒鏈表是否為空就行了,這節(jié)省了大量的CPU時間。這就是回調(diào)機制帶來的性能提升。

(2)select,poll每次調(diào)用都要把fd集合從用戶態(tài)往內(nèi)核態(tài)拷貝一次,epoll 通過 mmap  把內(nèi)核空間和用戶空間映射到同一塊內(nèi)存,省去了拷貝的操作。

應用舉例

  • Tornado:

  • 使用單線程的方式,避免線程切換的性能開銷,同時避免在使用一些函數(shù)接口時出現(xiàn)線程不安全的情況

  • 支持異步非阻塞網(wǎng)絡IO模型,避免主進程阻塞等待。

tornado 的 IOLoop 模塊 是異步機制的核心,它包含了一系列已經(jīng)打開的文件描述符和每個描述符的處理器 (handlers)。這些  handlers 就是對 select, poll , epoll等的封裝。(所以本質(zhì)上說是 IO 復用)

  • Django

沒有用異步,通過使用多進程的WSGI server(比如uWSGI)來實現(xiàn)并發(fā),這也是WSGI普遍的做法。

Linux后端服務器開發(fā)要學關于IO的哪些知識點

網(wǎng)絡IO是網(wǎng)絡通信的血管,數(shù)據(jù)是血液。血液的流動是不能離開血管的。

上述就是小編為大家分享的如何理解Linux操作系統(tǒng) IO 模式了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI