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

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

成都創(chuàng)新互聯(lián)自2013年起,先為遼陽縣等服務(wù)建站,遼陽縣等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為遼陽縣企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

 IO

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

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

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

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

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

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

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

關(guān)鍵概念理解

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

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

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

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

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

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

明確進(jìn)程狀態(tài)

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

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

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

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

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

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

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

阻塞IO模型:

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

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

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

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

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

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

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

非阻塞IO模型

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

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

IO復(fù)用模型:

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

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

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

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

異步IO模型

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

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

區(qū)別IO多路復(fù)用中的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ù)會(huì)阻塞,直到有描述符就緒(有數(shù)據(jù)  可讀、可寫、或者有except),或者超時(shí)(timeout指定等待時(shí)間,如果立即返回設(shè)為null即可),函數(shù)返回。當(dāng)select函數(shù)返回后,可以  通過遍歷fdset,來找到就緒的描述符

poll

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

epoll

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

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

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

控制某個(gè) 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ā)生的超時(shí)值;

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

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

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

應(yīng)用舉例

  • Tornado:

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

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

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

  • Django

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

Linux后端服務(wù)器開發(fā)要學(xué)關(guān)于IO的哪些知識(shí)點(diǎn)

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

上述就是小編為大家分享的如何理解Linux操作系統(tǒng) IO 模式了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

本文名稱:如何理解Linux操作系統(tǒng)IO模式
URL分享:http://muchs.cn/article2/gphcic.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器用戶體驗(yàn)、網(wǎng)站營銷、靜態(tài)網(wǎng)站、商城網(wǎng)站、品牌網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)