<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          深入聊聊Linux五種IO模型

          共 5977字,需瀏覽 12分鐘

           ·

          2022-07-16 15:37


          一、相關(guān)概念講解


          1、同步與異步


          同步就是一個任務(wù)的完成需要依賴另外一個任務(wù)時,只有等待被依賴的任務(wù)完成后,依賴的任務(wù)才能算完成,這是一種可靠的任務(wù)序列。要么成功都成功,失敗都失敗,兩個任務(wù)的狀態(tài)可以保持一致。

          異步是不需要等待被依賴的任務(wù)完成,只是通知被依賴的任務(wù)要完成什么工作,依賴的任務(wù)也立即執(zhí)行,只要自己完成了整個任務(wù)就算完成了。至于被依賴的任務(wù)最終是否真正完成,依賴它的任務(wù)無法確定,所以它是不可靠的任務(wù)序列。


          2、堵塞與非堵塞


          阻塞和非阻塞這兩個概念與程序(線程)等待消息通知(無所謂同步或者異步)時的狀態(tài)有關(guān)。也就是說阻塞與非阻塞主要是程序(線程)等待消息通知時的狀態(tài)角度來說的。
           
          阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當前線程會被掛起,一直處于等待消息通知,不能夠執(zhí)行其他業(yè)務(wù)。函數(shù)只有在得到結(jié)果之后才會返回。

          非阻塞和阻塞的概念相對應(yīng),指在不能立刻得到結(jié)果之前,該函數(shù)不會阻塞當前線程,而會立刻返回。雖然表面上看非阻塞的方式可以明顯的提高CPU的利用率,但是也帶了另外一種后果就是系統(tǒng)的線程切換增加。增加的CPU執(zhí)行時間能不能補償系統(tǒng)的切換成本需要好好評估。
           
          (a) 如果這個線程在等待當前函數(shù)返回時,仍在執(zhí)行其他消息處理,那這種情況就叫做同步非阻塞;

          (b) 如果這個線程在等待當前函數(shù)返回時,沒有執(zhí)行其他消息處理,而是處于掛起等待狀態(tài),那這種情況就叫做同步阻塞

          同步/異步關(guān)注的是消息通知的機制,而阻塞/非阻塞關(guān)注的是程序(線程)等待消息通知時的狀態(tài)


          3、用戶空間與內(nèi)核空間


          現(xiàn)在操作系統(tǒng)都是采用虛擬存儲器,那么對32位操作系統(tǒng)而言,它的尋址空間(虛擬存儲空間)為4G232次方)。操作系統(tǒng)的核心是內(nèi)核,獨立于普通的應(yīng)用程序,可以訪問受保護的內(nèi)存空間,也有訪問底層硬件設(shè)備的所有權(quán)限。為了保證用戶進程不能直接操作內(nèi)核(kernel),保證內(nèi)核的安全,操作系統(tǒng)將虛擬空間劃分為兩部分,一部分為內(nèi)核空間,一部分為用戶空間。針對linux操作系統(tǒng)而言,將最高的1G字節(jié)(從虛擬地址0xC00000000xFFFFFFFF),供內(nèi)核使用,稱為內(nèi)核空間,而將較低的3G字節(jié)(從虛擬地址0x000000000xBFFFFFFF),供各個進程使用,稱為用戶空間。

          4、進程切換


          為了控制進程的執(zhí)行,內(nèi)核必須有能力掛起正在CPU上運行的進程,并恢復(fù)以前掛起的某個進程的執(zhí)行。這種行為被稱為進程切換。因此可以說,任何進程都是在操作系統(tǒng)內(nèi)核的支持下運行的,是與內(nèi)核緊密相關(guān)的。
          從一個進程的運行轉(zhuǎn)到另一個進程上運行,這個過程中經(jīng)過下面這些變化:

          1、保存處理機上下文,包括程序計數(shù)器和其他寄存器。
          2、更新PCB信息。
          3、把進程的PCB移入相應(yīng)的隊列,如就緒、在某事件阻塞等隊列。
          4、選擇另一個進程執(zhí)行,并更新其PCB
          5、更新內(nèi)存管理的數(shù)據(jù)結(jié)構(gòu)。
          6、恢復(fù)處理機上下文。
          注:總而言之就是很耗資源


          5、進程的堵塞


          正在執(zhí)行的進程,由于期待的某些事件未發(fā)生,如請求系統(tǒng)資源失敗、等待某種操作的完成、新數(shù)據(jù)尚未到達或無新工作做等,則由系統(tǒng)自動執(zhí)行阻塞原語(Block),使自己由運行狀態(tài)變?yōu)樽枞麪顟B(tài)。可見,進程的阻塞是進程自身的一種主動行為,也因此只有處于運行態(tài)的進程(獲得CPU),才可能將其轉(zhuǎn)為阻塞狀態(tài)。當進程進入阻塞狀態(tài),是不占用CPU資源的


          6、文件描述符


          文件描述符(File descriptor)是計算機科學(xué)中的一個術(shù)語,是一個用于表述指向文件的引用的抽象化概念。

          文件描述符在形式上是一個非負整數(shù)。實際上,它是一個索引值指向內(nèi)核為每一個進程所維護的該進程打開文件的記錄表。當程序打開一個現(xiàn)有文件或者創(chuàng)建一個新文件時,內(nèi)核向進程返回一個文件描述符。在程序設(shè)計中,一些涉及底層的程序編寫往往會圍繞著文件描述符展開。但是文件描述符這一概念往往只適用于UNIX、Linux這樣的操作系統(tǒng)。


          7、緩存


          緩存 IO 又被稱作標準 IO,大多數(shù)文件系統(tǒng)的默認 IO 操作都是緩存 IO。在 Linux 的緩存 IO 機制中,操作系統(tǒng)會將 IO 的數(shù)據(jù)緩存在文件系統(tǒng)的頁緩存(page cache )中,也就是說,數(shù)據(jù)會先被拷貝到操作系統(tǒng)內(nèi)核的緩沖區(qū)中,然后才會從操作系統(tǒng)內(nèi)核的緩沖區(qū)拷貝到應(yīng)用程序的地址空間。

          緩存 IO 的缺點:

          數(shù)據(jù)在傳輸過程中需要在應(yīng)用程序地址空間和內(nèi)核進行多次數(shù)據(jù)拷貝操作,這些數(shù)據(jù)拷貝操作所帶來的 CPU 以及內(nèi)存開銷是非常大的。


          二、IO模型


          網(wǎng)絡(luò)IO的本質(zhì)是socket的讀取,socketlinux系統(tǒng)被抽象為流,IO可以理解為對流的操作。剛才說了,對于一次IO訪問(以read舉例),數(shù)據(jù)會先被拷貝到操作系統(tǒng)內(nèi)核的緩沖區(qū)中,然后才會從操作系統(tǒng)內(nèi)核的緩沖區(qū)拷貝到應(yīng)用程序的地址空間。

          所以說,當一個read操作發(fā)生時,它會經(jīng)歷兩個階段:

          第一階段:等待數(shù)據(jù)準備 (Waiting for the data to be ready)。
          第二階段:將數(shù)據(jù)從內(nèi)核拷貝到進程中 (Copying the data from the kernel to the process)。
           
          對于socket流而言,

          第一步:通常涉及等待網(wǎng)絡(luò)上的數(shù)據(jù)分組到達,然后被復(fù)制到內(nèi)核的某個緩沖區(qū)。
          第二步:把數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到應(yīng)用進程緩沖區(qū)。
           
          網(wǎng)絡(luò)應(yīng)用需要處理的無非就是兩大類問題,網(wǎng)絡(luò)IO,數(shù)據(jù)計算。相對于后者,網(wǎng)絡(luò)IO的延遲,給應(yīng)用帶來的性能瓶頸大于后者。

          網(wǎng)絡(luò)IO的模型大致有如下幾種:
          · 同步模型(synchronous IO
          · 阻塞IObloking IO
          · 非阻塞IOnon-blocking IO
          · 多路復(fù)用IOmultiplexing IO
          · 信號驅(qū)動式IOsignal-driven IO
          · 異步IOasynchronous IO注:由于signal driven IO在實際中并不常用,所以我這只提及剩下的四種IO Model。

          1、堵塞IO模型


          應(yīng)用程序調(diào)用一個 IO 函數(shù),導(dǎo)致應(yīng)用程序阻塞,等待數(shù)據(jù)準備好。 如果數(shù)據(jù)沒有準備好,一直等待…數(shù)據(jù)準備好了,從內(nèi)核拷貝到用戶空間,IO 函數(shù)返回成功指示。

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

          2、非堵塞IO模型

           
          我們把一個 SOCKET 接口設(shè)置為非阻塞就是告訴內(nèi)核,當所請求的 I/O 操作無法完成時,不要將進程睡眠,而是返回一個錯誤。這樣我們的 I/O 操作函數(shù)將不斷的測試數(shù)據(jù)是否已經(jīng)準備好,如果沒有準備好,繼續(xù)測試,直到數(shù)據(jù)準備好為止。在這個不斷測試的過程中,會大量的占用 CPU 的時間。上述模型絕不被推薦。


          3、IO 復(fù)用模型

           
          由于同步非阻塞方式需要不斷主動輪詢,輪詢占據(jù)了很大一部分過程,輪詢會消耗大量的CPU時間,而 “后臺” 可能有多個任務(wù)在同時進行,人們就想到了循環(huán)查詢多個任務(wù)的完成狀態(tài),只要有任何一個任務(wù)完成,就去處理它。如果輪詢不是進程的用戶態(tài),而是有人幫忙就好了。那么這就是所謂的 IO 多路復(fù)用”
           
          IO多路復(fù)用有兩個特別的系統(tǒng)調(diào)用selectpollepoll函數(shù)。select調(diào)用是內(nèi)核級別的,select輪詢相對非阻塞的輪詢的區(qū)別在于---前者可以等待多個socket,能實現(xiàn)同時對多個IO端口進行監(jiān)聽,當其中任何一個socket的數(shù)據(jù)準好了,就能返回進行可讀,然后進程再進行recvform系統(tǒng)調(diào)用,將數(shù)據(jù)由內(nèi)核拷貝到用戶進程,當然這個過程是阻塞的。selectpoll調(diào)用之后,會阻塞進程,與blocking IO阻塞不同在于,此時的select不是等到socket數(shù)據(jù)全部到達再處理而是有了一部分數(shù)據(jù)就會調(diào)用用戶進程來處理。如何知道有一部分數(shù)據(jù)到達了呢?監(jiān)視的事情交給了內(nèi)核,內(nèi)核負責(zé)數(shù)據(jù)到達的處理。也可以理解為"非阻塞"吧。

          I/O復(fù)用模型會用到selectpollepoll函數(shù),這幾個函數(shù)也會使進程阻塞,但是和阻塞I/O所不同的的,這兩個函數(shù)可以同時阻塞多個I/O操作。而且可以同時對多個讀操作,多個寫操作的I/O函數(shù)進行檢測,直到有數(shù)據(jù)可讀或可寫時(注意不是全部數(shù)據(jù)可讀或可寫),才真正調(diào)用I/O操作函數(shù)。

          對于多路復(fù)用,也就是輪詢多個socket。多路復(fù)用既然可以處理多個IO,也就帶來了新的問題,多個IO之間的順序變得不確定了,當然也可以針對不同的編號。
           
          在I/O編程過程中,當需要同時處理多個客戶端接入請求時,可以利用多線程或者I/O多路復(fù)用技術(shù)進行處理。I/O多路復(fù)用技術(shù)通過把多個I/O的阻塞復(fù)用到同一個select的阻塞上,從而使得系統(tǒng)在單線程的情況下可以同時處理多個客戶端請求。與傳統(tǒng)的多線程/多進程模型比,I/O多路復(fù)用的最大優(yōu)勢是系統(tǒng)開銷小,系統(tǒng)不需要創(chuàng)建新的額外進程或者線程,也不需要維護這些進程和線程的運行,降底了系統(tǒng)的維護工作量,節(jié)省了系統(tǒng)資源,I/O多路復(fù)用的主要應(yīng)用場景如下:

          1、服務(wù)器需要同時處理多個處于監(jiān)聽狀態(tài)或者多個連接狀態(tài)的套接字。
          2、服務(wù)器需要同時處理多種網(wǎng)絡(luò)協(xié)議的套接字。

          此時你是不是想到的了redis如何做的啊,redis用的就是多路復(fù)用。
           

          3、信號驅(qū)動IO

           

          簡介:兩次調(diào)用,兩次返回;

          首先我們允許套接口進行信號驅(qū)動 I/O,并安裝一個信號處理函數(shù),進程繼續(xù)運行并不阻塞。當數(shù)據(jù)準備好時,進程會收到一個 SIGIO 信號,可以在信號處理函數(shù)中調(diào)用 I/O 操作函數(shù)處理數(shù)據(jù)。


          4、異步IO模型

           
          相對于同步IO,異步IO不是順序執(zhí)行。用戶進程進行aio_read系統(tǒng)調(diào)用之后,無論內(nèi)核數(shù)據(jù)是否準備好,都會直接返回給用戶進程,然后用戶態(tài)進程可以去做別的事情。等到socket數(shù)據(jù)準備好了,內(nèi)核直接復(fù)制數(shù)據(jù)給進程,然后從內(nèi)核向進程發(fā)送通知。IO兩個階段,進程都是非阻塞的。

          Linux提供了AIO庫函數(shù)實現(xiàn)異步,但是用的很少。目前有很多開源的異步IO庫,例如libeventlibevlibuv
           
           

          5、5種I/O模型的比較

           
          不同 I/O 模型的區(qū)別,其實主要在等待數(shù)據(jù)和數(shù)據(jù)復(fù)制這兩個時間段不同,圖形中已經(jīng)表示得很清楚了。

          通過上面的圖片,可以發(fā)現(xiàn)non-blocking IO和asynchronous IO的區(qū)別還是很明顯的。在non-blocking IO中,雖然進程大部分時間都不會被block,但是它仍然要求進程去主動的check,并且當數(shù)據(jù)準備完成以后,也需要進程主動的再次調(diào)用recvfrom來將數(shù)據(jù)拷貝到用戶內(nèi)存。而asynchronous IO則完全不同。它就像是用戶進程將整個IO操作交給了他人(kernel)完成,然后他人做完后發(fā)信號通知。在此期間,用戶進程不需要去檢查IO操作的狀態(tài),也不需要主動的去拷貝數(shù)據(jù)。
           
           
          同步非阻塞方式相比同步阻塞方式:

          優(yōu)點:能夠在等待任務(wù)完成的時間里干其他活了(包括提交其他任務(wù),也就是 “后臺” 可以有多個任務(wù)在同時執(zhí)行)。

          缺點:任務(wù)完成的響應(yīng)延遲增大了,因為每過一段時間才去輪詢一次read操作,而任務(wù)可能在兩次輪詢之間的任意時間完成。這會導(dǎo)致整體數(shù)據(jù)吞吐量的降低。

          三、select 、poll 、epoll的區(qū)別?


          1、支持一個進程所能打開的最大連接數(shù)
           

          2、FD (文件描述符)劇增后帶來的 IO 效率問題
           
          3、消息傳遞方式
           

          綜上,在選擇select,pollepoll 時要根據(jù)具體的使用場合以及這三種方式的自身特點。
          1、表面上看 epoll 的性能最好,但是在連接數(shù)少并且連接都十分活躍的情況下,select 和 poll 的性能可能比 epoll 好,畢竟 epoll 的通知機制需要很多函數(shù)回調(diào)。
          2、select 低效是因為每次它都需要輪詢。但低效也是相對的,視情況而定,也可通過良好的設(shè)計改善
           
          補充知識點:

          Level_triggered(水平觸發(fā)):當被監(jiān)控的文件描述符上有可讀寫事件發(fā)生時,epoll_wait()會通知處理程序去讀寫。如果這次沒有把數(shù)據(jù)一次性全部讀寫完(如讀寫緩沖區(qū)太小),那么下次調(diào)用 epoll_wait()時,它還會通知你在上沒讀寫完的文件描述符上繼續(xù)讀寫,當然如果你一直不去讀寫,它會一直通知你!如果系統(tǒng)中有大量你不需要讀寫的就緒文件描述符,而它們每次都會返回,這樣會大大降低處理程序檢索自己關(guān)心的就緒文件描述符的效率!

          Edge_triggered(邊緣觸發(fā)):當被監(jiān)控的文件描述符上有可讀寫事件發(fā)生時,epoll_wait()會通知處理程序去讀寫。如果這次沒有把數(shù)據(jù)全部讀寫完(如讀寫緩沖區(qū)太小),那么下次調(diào)用 epoll_wait()時,它不會通知你,也就是它只會通知你一次,直到該文件描述符上出現(xiàn)第二次可讀寫事件才會通知你!這種模式比水平觸發(fā)效率高,系統(tǒng)不會充斥大量你不關(guān)心的就緒文件描述符!

          select(),poll()模型都是水平觸發(fā)模式,信號驅(qū)動IO是邊緣觸發(fā)模式,epoll()模型即支持水平觸發(fā),也支持邊緣觸發(fā),默認是水平觸發(fā)。

          推薦閱讀:

          世界的真實格局分析,地球人類社會底層運行原理

          不是你需要中臺,而是一名合格的架構(gòu)師(附各大廠中臺建設(shè)PPT)

          企業(yè)IT技術(shù)架構(gòu)規(guī)劃方案

          論數(shù)字化轉(zhuǎn)型——轉(zhuǎn)什么,如何轉(zhuǎn)?

          華為干部與人才發(fā)展手冊(附PPT)

          企業(yè)10大管理流程圖,數(shù)字化轉(zhuǎn)型從業(yè)者必備!

          【中臺實踐】華為大數(shù)據(jù)中臺架構(gòu)分享.pdf

          華為的數(shù)字化轉(zhuǎn)型方法論

          華為如何實施數(shù)字化轉(zhuǎn)型(附PPT)

          超詳細280頁Docker實戰(zhàn)文檔!開放下載

          華為大數(shù)據(jù)解決方案(PPT)

          瀏覽 46
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲欧美另类色图 | 韩日三级毛片 | 欧美日韩爽 | 国产做受 91电影 | 操操色网 |