日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

聊聊 Linux 中的五种 IO 模型

發(fā)布時(shí)間:2025/7/25 linux 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 聊聊 Linux 中的五种 IO 模型 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

聊聊 Linux 中的五種 IO 模型

分享到:0 本文作者:?伯樂在線?-?陶邦仁?。未經(jīng)作者許可,禁止轉(zhuǎn)載!
歡迎加入伯樂在線?專欄作者。

上一篇《聊聊同步、異步、阻塞與非阻塞》已經(jīng)通俗的講解了,要理解同步、異步、阻塞與非阻塞重要的兩個(gè)概念點(diǎn)了,沒有看過的,建議先看這篇博文理解這兩個(gè)概念點(diǎn)。在認(rèn)知上,建立統(tǒng)一的模型。這樣,大家在繼續(xù)看本篇時(shí),才不會(huì)理解有偏差。

那么,在正式開始講Linux IO模型前,比如:同步IO和異步IO,阻塞IO和非阻塞IO分別是什么,到底有什么區(qū)別?不同的人在不同的上下文下給出的答案是不同的。所以先限定一下本文的上下文。

1 概念說(shuō)明

在進(jìn)行解釋之前,首先要說(shuō)明幾個(gè)概念:

用戶空間和內(nèi)核空間

進(jìn)程切換

進(jìn)程的阻塞

文件描述符

緩存 IO

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

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

1.2 進(jìn)程切換

為了控制進(jìn)程的執(zhí)行,內(nèi)核必須有能力掛起正在CPU上運(yùn)行的進(jìn)程,并恢復(fù)以前掛起的某個(gè)進(jìn)程的執(zhí)行。這種行為被稱為進(jìn)程切換。因此可以說(shuō),任何進(jìn)程都是在操作系統(tǒng)內(nèi)核的支持下運(yùn)行的,是與內(nèi)核緊密相關(guān)的。

從一個(gè)進(jìn)程的運(yùn)行轉(zhuǎn)到另一個(gè)進(jìn)程上運(yùn)行,這個(gè)過程中經(jīng)過下面這些變化:

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

    1.3 進(jìn)程的阻塞

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

    1.4 文件描述符fd

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

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

    1.5 緩存 IO

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

    緩存 IO 的缺點(diǎn):

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

    2 Linux IO模型

    網(wǎng)絡(luò)IO的本質(zhì)是socket的讀取,socket在linux系統(tǒng)被抽象為流,IO可以理解為對(duì)流的操作。剛才說(shuō)了,對(duì)于一次IO訪問(以read舉例),數(shù)據(jù)會(huì)先被拷貝到操作系統(tǒng)內(nèi)核的緩沖區(qū)中,然后才會(huì)從操作系統(tǒng)內(nèi)核的緩沖區(qū)拷貝到應(yīng)用程序的地址空間。所以說(shuō),當(dāng)一個(gè)read操作發(fā)生時(shí),它會(huì)經(jīng)歷兩個(gè)階段:

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

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

    • 同步模型(synchronous IO)
    • 阻塞IO(bloking IO)
    • 非阻塞IO(non-blocking IO)
    • 多路復(fù)用IO(multiplexing IO)
    • 信號(hào)驅(qū)動(dòng)式IO(signal-driven IO)
    • 異步IO(asynchronous IO)

    注:由于signal driven IO在實(shí)際中并不常用,所以我這只提及剩下的四種IO Model。

    在深入介紹Linux IO各種模型之前,讓我們先來(lái)探索一下基本 Linux IO 模型的簡(jiǎn)單矩陣。如下圖所示:

    每個(gè) IO 模型都有自己的使用模式,它們對(duì)于特定的應(yīng)用程序都有自己的優(yōu)點(diǎn)。本節(jié)將簡(jiǎn)要對(duì)其一一進(jìn)行介紹。常見的IO模型有阻塞、非阻塞、IO多路復(fù)用,異步。以一個(gè)生動(dòng)形象的例子來(lái)說(shuō)明這四個(gè)概念。周末我和女友去逛街,中午餓了,我們準(zhǔn)備去吃飯。周末人多,吃飯需要排隊(duì),我和女友有以下幾種方案。

    2.1 同步阻塞 IO(blocking IO)

    2.1.1 場(chǎng)景描述

    我和女友點(diǎn)完餐后,不知道什么時(shí)候能做好,只好坐在餐廳里面等,直到做好,然后吃完才離開。女友本想還和我一起逛街的,但是不知道飯能什么時(shí)候做好,只好和我一起在餐廳等,而不能去逛街,直到吃完飯才能去逛街,中間等待做飯的時(shí)間浪費(fèi)掉了。這就是典型的阻塞。

    2.1.2 網(wǎng)絡(luò)模型

    同步阻塞 IO 模型是最常用的一個(gè)模型,也是最簡(jiǎn)單的模型。在linux中,默認(rèn)情況下所有的socket都是blocking。它符合人們最常見的思考邏輯。阻塞就是進(jìn)程 "被" 休息, CPU處理其它進(jìn)程去了。

    在這個(gè)IO模型中,用戶空間的應(yīng)用程序執(zhí)行一個(gè)系統(tǒng)調(diào)用(recvform),這會(huì)導(dǎo)致應(yīng)用程序阻塞,什么也不干,直到數(shù)據(jù)準(zhǔn)備好,并且將數(shù)據(jù)從內(nèi)核復(fù)制到用戶進(jìn)程,最后進(jìn)程再處理數(shù)據(jù),在等待數(shù)據(jù)到處理數(shù)據(jù)的兩個(gè)階段,整個(gè)進(jìn)程都被阻塞。不能處理別的網(wǎng)絡(luò)IO。調(diào)用應(yīng)用程序處于一種不再消費(fèi) CPU 而只是簡(jiǎn)單等待響應(yīng)的狀態(tài),因此從處理的角度來(lái)看,這是非常有效的。在調(diào)用recv()/recvfrom()函數(shù)時(shí),發(fā)生在內(nèi)核中等待數(shù)據(jù)和復(fù)制數(shù)據(jù)的過程,大致如下圖:

    2.1.3 流程描述

    當(dāng)用戶進(jìn)程調(diào)用了recv()/recvfrom()這個(gè)系統(tǒng)調(diào)用,kernel就開始了IO的第一個(gè)階段:準(zhǔn)備數(shù)據(jù)(對(duì)于網(wǎng)絡(luò)IO來(lái)說(shuō),很多時(shí)候數(shù)據(jù)在一開始還沒有到達(dá)。比如,還沒有收到一個(gè)完整的UDP包。這個(gè)時(shí)候kernel就要等待足夠的數(shù)據(jù)到來(lái))。這個(gè)過程需要等待,也就是說(shuō)數(shù)據(jù)被拷貝到操作系統(tǒng)內(nèi)核的緩沖區(qū)中是需要一個(gè)過程的。而在用戶進(jìn)程這邊,整個(gè)進(jìn)程會(huì)被阻塞(當(dāng)然,是進(jìn)程自己選擇的阻塞)。第二個(gè)階段:當(dāng)kernel一直等到數(shù)據(jù)準(zhǔn)備好了,它就會(huì)將數(shù)據(jù)從kernel中拷貝到用戶內(nèi)存,然后kernel返回結(jié)果,用戶進(jìn)程才解除block的狀態(tài),重新運(yùn)行起來(lái)。

    所以,blocking IO的特點(diǎn)就是在IO執(zhí)行的兩個(gè)階段都被block了。

    優(yōu)點(diǎn):

  • 能夠及時(shí)返回?cái)?shù)據(jù),無(wú)延遲;
  • 對(duì)內(nèi)核開發(fā)者來(lái)說(shuō)這是省事了;
  • 缺點(diǎn):

  • 對(duì)用戶來(lái)說(shuō)處于等待就要付出性能的代價(jià)了;
  • 2.2 同步非阻塞 IO(nonblocking IO)

    2.2.1 場(chǎng)景描述

    我女友不甘心白白在這等,又想去逛商場(chǎng),又擔(dān)心飯好了。所以我們逛一會(huì),回來(lái)詢問服務(wù)員飯好了沒有,來(lái)來(lái)回回好多次,飯都還沒吃都快累死了啦。這就是非阻塞。需要不斷的詢問,是否準(zhǔn)備好了。

    2.2.2 網(wǎng)絡(luò)模型

    同步非阻塞就是 “每隔一會(huì)兒瞄一眼進(jìn)度條” 的輪詢(polling)方式。在這種模型中,設(shè)備是以非阻塞的形式打開的。這意味著 IO 操作不會(huì)立即完成,read 操作可能會(huì)返回一個(gè)錯(cuò)誤代碼,說(shuō)明這個(gè)命令不能立即滿足(EAGAIN 或 EWOULDBLOCK)。

    在網(wǎng)絡(luò)IO時(shí)候,非阻塞IO也會(huì)進(jìn)行recvform系統(tǒng)調(diào)用,檢查數(shù)據(jù)是否準(zhǔn)備好,與阻塞IO不一樣,”非阻塞將大的整片時(shí)間的阻塞分成N多的小的阻塞, 所以進(jìn)程不斷地有機(jī)會(huì) ‘被’ CPU光顧”。

    也就是說(shuō)非阻塞的recvform系統(tǒng)調(diào)用調(diào)用之后,進(jìn)程并沒有被阻塞,內(nèi)核馬上返回給進(jìn)程,如果數(shù)據(jù)還沒準(zhǔn)備好,此時(shí)會(huì)返回一個(gè)error。進(jìn)程在返回之后,可以干點(diǎn)別的事情,然后再發(fā)起recvform系統(tǒng)調(diào)用。重復(fù)上面的過程,循環(huán)往復(fù)的進(jìn)行recvform系統(tǒng)調(diào)用。這個(gè)過程通常被稱之為輪詢。輪詢檢查內(nèi)核數(shù)據(jù),直到數(shù)據(jù)準(zhǔn)備好,再拷貝數(shù)據(jù)到進(jìn)程,進(jìn)行數(shù)據(jù)處理。需要注意,拷貝數(shù)據(jù)整個(gè)過程,進(jìn)程仍然是屬于阻塞的狀態(tài)。

    在linux下,可以通過設(shè)置socket使其變?yōu)閚on-blocking。當(dāng)對(duì)一個(gè)non-blocking socket執(zhí)行讀操作時(shí),流程如圖所示:

    2.2.3 流程描述

    當(dāng)用戶進(jìn)程發(fā)出read操作時(shí),如果kernel中的數(shù)據(jù)還沒有準(zhǔn)備好,那么它并不會(huì)block用戶進(jìn)程,而是立刻返回一個(gè)error。從用戶進(jìn)程角度講,它發(fā)起一個(gè)read操作后,并不需要等待,而是馬上就得到了一個(gè)結(jié)果。用戶進(jìn)程判斷結(jié)果是一個(gè)error時(shí),它就知道數(shù)據(jù)還沒有準(zhǔn)備好,于是它可以再次發(fā)送read操作。一旦kernel中的數(shù)據(jù)準(zhǔn)備好了,并且又再次收到了用戶進(jìn)程的system call,那么它馬上就將數(shù)據(jù)拷貝到了用戶內(nèi)存,然后返回。

    所以,nonblocking IO的特點(diǎn)是用戶進(jìn)程需要不斷的主動(dòng)詢問kernel數(shù)據(jù)好了沒有。

    同步非阻塞方式相比同步阻塞方式:

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

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

    2.3 IO 多路復(fù)用( IO multiplexing)

    2.3.1 場(chǎng)景描述

    與第二個(gè)方案差不多,餐廳安裝了電子屏幕用來(lái)顯示點(diǎn)餐的狀態(tài),這樣我和女友逛街一會(huì),回來(lái)就不用去詢問服務(wù)員了,直接看電子屏幕就可以了。這樣每個(gè)人的餐是否好了,都直接看電子屏幕就可以了,這就是典型的IO多路復(fù)用。

    2.3.2 網(wǎng)絡(luò)模型

    由于同步非阻塞方式需要不斷主動(dòng)輪詢,輪詢占據(jù)了很大一部分過程,輪詢會(huì)消耗大量的CPU時(shí)間,而 “后臺(tái)” 可能有多個(gè)任務(wù)在同時(shí)進(jìn)行,人們就想到了循環(huán)查詢多個(gè)任務(wù)的完成狀態(tài),只要有任何一個(gè)任務(wù)完成,就去處理它。如果輪詢不是進(jìn)程的用戶態(tài),而是有人幫忙就好了。那么這就是所謂的 “IO 多路復(fù)用”。UNIX/Linux 下的 select、poll、epoll 就是干這個(gè)的(epoll 比 poll、select 效率高,做的事情是一樣的)。

    IO多路復(fù)用有兩個(gè)特別的系統(tǒng)調(diào)用select、poll、epoll函數(shù)。select調(diào)用是內(nèi)核級(jí)別的,select輪詢相對(duì)非阻塞的輪詢的區(qū)別在于—前者可以等待多個(gè)socket,能實(shí)現(xiàn)同時(shí)對(duì)多個(gè)IO端口進(jìn)行監(jiān)聽,當(dāng)其中任何一個(gè)socket的數(shù)據(jù)準(zhǔn)好了,就能返回進(jìn)行可讀,然后進(jìn)程再進(jìn)行recvform系統(tǒng)調(diào)用,將數(shù)據(jù)由內(nèi)核拷貝到用戶進(jìn)程,當(dāng)然這個(gè)過程是阻塞的。select或poll調(diào)用之后,會(huì)阻塞進(jìn)程,與blocking IO阻塞不同在于,此時(shí)的select不是等到socket數(shù)據(jù)全部到達(dá)再處理, 而是有了一部分?jǐn)?shù)據(jù)就會(huì)調(diào)用用戶進(jìn)程來(lái)處理。如何知道有一部分?jǐn)?shù)據(jù)到達(dá)了呢?監(jiān)視的事情交給了內(nèi)核,內(nèi)核負(fù)責(zé)數(shù)據(jù)到達(dá)的處理。也可以理解為"非阻塞"吧。

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

    對(duì)于多路復(fù)用,也就是輪詢多個(gè)socket。多路復(fù)用既然可以處理多個(gè)IO,也就帶來(lái)了新的問題,多個(gè)IO之間的順序變得不確定了,當(dāng)然也可以針對(duì)不同的編號(hào)。具體流程,如下圖所示:

    2.3.3 流程描述

    IO multiplexing就是我們說(shuō)的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)程。

    當(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)程。

    多路復(fù)用的特點(diǎn)是通過一種機(jī)制一個(gè)進(jìn)程能同時(shí)等待IO文件描述符,內(nèi)核監(jiān)視這些文件描述符(套接字描述符),其中的任意一個(gè)進(jìn)入讀就緒狀態(tài),select, poll,epoll函數(shù)就可以返回。對(duì)于監(jiān)視的方式,又可以分為 select, poll, epoll三種方式。

    上面的圖和blocking IO的圖其實(shí)并沒有太大的不同,事實(shí)上,還更差一些。因?yàn)檫@里需要使用兩個(gè)system call (select 和 recvfrom),而blocking IO只調(diào)用了一個(gè)system call (recvfrom)。但是,用select的優(yōu)勢(shì)在于它可以同時(shí)處理多個(gè)connection。

    所以,如果處理的連接數(shù)不是很高的話,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延遲還更大。(select/epoll的優(yōu)勢(shì)并不是對(duì)于單個(gè)連接能處理得更快,而是在于能處理更多的連接。)

    在IO multiplexing Model中,實(shí)際中,對(duì)于每一個(gè)socket,一般都設(shè)置成為non-blocking,但是,如上圖所示,整個(gè)用戶的process其實(shí)是一直被block的。只不過process是被select這個(gè)函數(shù)block,而不是被socket IO給block。所以IO多路復(fù)用是阻塞在select,epoll這樣的系統(tǒng)調(diào)用之上,而沒有阻塞在真正的I/O系統(tǒng)調(diào)用如recvfrom之上。

    了解了前面三種IO模式,在用戶進(jìn)程進(jìn)行系統(tǒng)調(diào)用的時(shí)候,他們?cè)诘却龜?shù)據(jù)到來(lái)的時(shí)候,處理的方式不一樣,直接等待,輪詢,select或poll輪詢,兩個(gè)階段過程:

    第一個(gè)階段有的阻塞,有的不阻塞,有的可以阻塞又可以不阻塞。

    第二個(gè)階段都是阻塞的。

    從整個(gè)IO過程來(lái)看,他們都是順序執(zhí)行的,因此可以歸為同步模型(synchronous)。都是進(jìn)程主動(dòng)等待且向內(nèi)核檢查狀態(tài)。【此句很重要!!!】

    高并發(fā)的程序一般使用同步非阻塞方式而非多線程 + 同步阻塞方式。要理解這一點(diǎn),首先要扯到并發(fā)和并行的區(qū)別。比如去某部門辦事需要依次去幾個(gè)窗口,辦事大廳里的人數(shù)就是并發(fā)數(shù),而窗口個(gè)數(shù)就是并行度。也就是說(shuō)并發(fā)數(shù)是指同時(shí)進(jìn)行的任務(wù)數(shù)(如同時(shí)服務(wù)的 HTTP 請(qǐng)求),而并行數(shù)是可以同時(shí)工作的物理資源數(shù)量(如 CPU 核數(shù))。通過合理調(diào)度任務(wù)的不同階段,并發(fā)數(shù)可以遠(yuǎn)遠(yuǎn)大于并行度,這就是區(qū)區(qū)幾個(gè) CPU 可以支持上萬(wàn)個(gè)用戶并發(fā)請(qǐng)求的奧秘。在這種高并發(fā)的情況下,為每個(gè)任務(wù)(用戶請(qǐng)求)創(chuàng)建一個(gè)進(jìn)程或線程的開銷非常大。而同步非阻塞方式可以把多個(gè) IO 請(qǐng)求丟到后臺(tái)去,這就可以在一個(gè)進(jìn)程里服務(wù)大量的并發(fā) IO 請(qǐng)求。

    注意:IO多路復(fù)用是同步阻塞模型還是異步阻塞模型,在此給大家分析下:

    此處仍然不太清楚的,強(qiáng)烈建議大家在細(xì)究《聊聊同步、異步、阻塞與非阻塞》中講同步與異步的根本性區(qū)別,同步是需要主動(dòng)等待消息通知,而異步則是被動(dòng)接收消息通知,通過回調(diào)、通知、狀態(tài)等方式來(lái)被動(dòng)獲取消息。IO多路復(fù)用在阻塞到select階段時(shí),用戶進(jìn)程是主動(dòng)等待并調(diào)用select函數(shù)獲取數(shù)據(jù)就緒狀態(tài)消息,并且其進(jìn)程狀態(tài)為阻塞。所以,把IO多路復(fù)用歸為同步阻塞模式。

    2.4 信號(hào)驅(qū)動(dòng)式IO(signal-driven IO)

    信號(hào)驅(qū)動(dòng)式I/O:首先我們?cè)试SSocket進(jìn)行信號(hào)驅(qū)動(dòng)IO,并安裝一個(gè)信號(hào)處理函數(shù),進(jìn)程繼續(xù)運(yùn)行并不阻塞。當(dāng)數(shù)據(jù)準(zhǔn)備好時(shí),進(jìn)程會(huì)收到一個(gè)SIGIO信號(hào),可以在信號(hào)處理函數(shù)中調(diào)用I/O操作函數(shù)處理數(shù)據(jù)。過程如下圖所示:

    2.5 異步非阻塞 IO(asynchronous IO)

    2.5.1 場(chǎng)景描述

    女友不想逛街,又餐廳太吵了,回家好好休息一下。于是我們叫外賣,打個(gè)電話點(diǎn)餐,然后我和女友可以在家好好休息一下,飯好了送貨員送到家里來(lái)。這就是典型的異步,只需要打個(gè)電話說(shuō)一下,然后可以做自己的事情,飯好了就送來(lái)了。

    2.5.2 網(wǎng)絡(luò)模型

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

    Linux提供了AIO庫(kù)函數(shù)實(shí)現(xiàn)異步,但是用的很少。目前有很多開源的異步IO庫(kù),例如libevent、libev、libuv。異步過程如下圖所示:

    2.5.3 流程描述

    用戶進(jìn)程發(fā)起aio_read操作之后,立刻就可以開始去做其它的事。而另一方面,從kernel的角度,當(dāng)它受到一個(gè)asynchronous read之后,首先它會(huì)立刻返回,所以不會(huì)對(duì)用戶進(jìn)程產(chǎn)生任何block。然后,kernel會(huì)等待數(shù)據(jù)準(zhǔn)備完成,然后將數(shù)據(jù)拷貝到用戶內(nèi)存,當(dāng)這一切都完成之后,kernel會(huì)給用戶進(jìn)程發(fā)送一個(gè)signal或執(zhí)行一個(gè)基于線程的回調(diào)函數(shù)來(lái)完成這次 IO 處理過程,告訴它read操作完成了。

    在 Linux 中,通知的方式是 “信號(hào)”:

    如果這個(gè)進(jìn)程正在用戶態(tài)忙著做別的事(例如在計(jì)算兩個(gè)矩陣的乘積),那就強(qiáng)行打斷之,調(diào)用事先注冊(cè)的信號(hào)處理函數(shù),這個(gè)函數(shù)可以決定何時(shí)以及如何處理這個(gè)異步任務(wù)。由于信號(hào)處理函數(shù)是突然闖進(jìn)來(lái)的,因此跟中斷處理程序一樣,有很多事情是不能做的,因此保險(xiǎn)起見,一般是把事件 “登記” 一下放進(jìn)隊(duì)列,然后返回該進(jìn)程原來(lái)在做的事。

    如果這個(gè)進(jìn)程正在內(nèi)核態(tài)忙著做別的事,例如以同步阻塞方式讀寫磁盤,那就只好把這個(gè)通知掛起來(lái)了,等到內(nèi)核態(tài)的事情忙完了,快要回到用戶態(tài)的時(shí)候,再觸發(fā)信號(hào)通知。

    如果這個(gè)進(jìn)程現(xiàn)在被掛起了,例如無(wú)事可做 sleep 了,那就把這個(gè)進(jìn)程喚醒,下次有 CPU 空閑的時(shí)候,就會(huì)調(diào)度到這個(gè)進(jìn)程,觸發(fā)信號(hào)通知。

    異步 API 說(shuō)來(lái)輕巧,做來(lái)難,這主要是對(duì) API 的實(shí)現(xiàn)者而言的。Linux 的異步 IO(AIO)支持是 2.6.22 才引入的,還有很多系統(tǒng)調(diào)用不支持異步 IO。Linux 的異步 IO 最初是為數(shù)據(jù)庫(kù)設(shè)計(jì)的,因此通過異步 IO 的讀寫操作不會(huì)被緩存或緩沖,這就無(wú)法利用操作系統(tǒng)的緩存與緩沖機(jī)制。

    很多人把 Linux 的 O_NONBLOCK 認(rèn)為是異步方式,但事實(shí)上這是前面講的同步非阻塞方式。需要指出的是,雖然 Linux 上的 IO API 略顯粗糙,但每種編程框架都有封裝好的異步 IO 實(shí)現(xiàn)。操作系統(tǒng)少做事,把更多的自由留給用戶,正是 UNIX 的設(shè)計(jì)哲學(xué),也是 Linux 上編程框架百花齊放的一個(gè)原因。

    從前面 IO 模型的分類中,我們可以看出 AIO 的動(dòng)機(jī):

    同步阻塞模型需要在 IO 操作開始時(shí)阻塞應(yīng)用程序。這意味著不可能同時(shí)重疊進(jìn)行處理和 IO 操作。

    同步非阻塞模型允許處理和 IO 操作重疊進(jìn)行,但是這需要應(yīng)用程序根據(jù)重現(xiàn)的規(guī)則來(lái)檢查 IO 操作的狀態(tài)。

    這樣就剩下異步非阻塞 IO 了,它允許處理和 IO 操作重疊進(jìn)行,包括 IO 操作完成的通知。

    IO多路復(fù)用除了需要阻塞之外,select 函數(shù)所提供的功能(異步阻塞 IO)與 AIO 類似。不過,它是對(duì)通知事件進(jìn)行阻塞,而不是對(duì) IO 調(diào)用進(jìn)行阻塞。

    2.6 關(guān)于異步阻塞

    有時(shí)我們的 API 只提供異步通知方式,例如在 node.js 里,但業(yè)務(wù)邏輯需要的是做完一件事后做另一件事,例如數(shù)據(jù)庫(kù)連接初始化后才能開始接受用戶的 HTTP 請(qǐng)求。這樣的業(yè)務(wù)邏輯就需要調(diào)用者是以阻塞方式來(lái)工作。

    為了在異步環(huán)境里模擬 “順序執(zhí)行” 的效果,就需要把同步代碼轉(zhuǎn)換成異步形式,這稱為 CPS(Continuation Passing Style)變換。BYVoid 大神的?continuation.js?庫(kù)就是一個(gè) CPS 變換的工具。用戶只需用比較符合人類常理的同步方式書寫代碼,CPS 變換器會(huì)把它轉(zhuǎn)換成層層嵌套的異步回調(diào)形式。

    另外一種使用阻塞方式的理由是降低響應(yīng)延遲。如果采用非阻塞方式,一個(gè)任務(wù) A 被提交到后臺(tái),就開始做另一件事 B,但 B 還沒做完,A 就完成了,這時(shí)要想讓 A 的完成事件被盡快處理(比如 A 是個(gè)緊急事務(wù)),要么丟棄做到一半的 B,要么保存 B 的中間狀態(tài)并切換回 A,任務(wù)的切換是需要時(shí)間的(不管是從磁盤載入到內(nèi)存,還是從內(nèi)存載入到高速緩存),這勢(shì)必降低 A 的響應(yīng)速度。因此,對(duì)實(shí)時(shí)系統(tǒng)或者延遲敏感的事務(wù),有時(shí)采用阻塞方式比非阻塞方式更好。

    2.7 五種IO模型


    總結(jié)

    以上是生活随笔為你收集整理的聊聊 Linux 中的五种 IO 模型的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 丰满熟妇人妻中文字幕 | 性少妇videosexfreexxx片 | 亚洲激情自拍 | 欧美日韩一区不卡 | 国产做爰免费视频观看 | 久久久成 | 亚洲毛片在线观看 | 少妇裸体淫交视频免费看高清 | 亚洲国产精品无码久久 | 91爱爱影院 | avtt一区| 午夜成人免费影院 | xxxx日韩 | 四虎激情 | 岛国午夜视频 | 视频二区在线观看 | 91看大片 | 日韩黄色在线播放 | 另类小说婷婷 | 亚洲性欧美| 欧美女优视频 | 日本精品国产 | 欧美日本一道 | 亚洲成在人 | 国产老头和老头xxxx× | www夜插内射视频网站 | 天堂在线网 | 美国av片 | 激情xxx| 最新国产毛片 | 另类一区二区三区 | 国产8区| 黄色录像二级片 | 亚洲综合图片一区 | 风流少妇| 色花av| 三级大片在线观看 | 国产精品99久久久久久久 | 日本精品在线播放 | 久色影视| 一区二区在线视频免费观看 | 国产粉嫩呻吟一区二区三区 | 欧美日韩成人网 | 少妇愉情理伦片bd | 美女爱爱视频 | xxx一区| 4438x亚洲 | 熟女俱乐部一区二区 | 国产精品久久伊人 | 国产一区二区在线观看视频 | 亚洲日日夜夜 | 日本福利片在线观看 | 精品中文字幕视频 | 国产免费小视频 | 一区二区三区在线播放 | 天天干天天操天天 | 亚洲熟妇丰满大屁股熟妇 | 欧美在线一| 成年人免费看黄色 | 日本一品道 | 日韩毛片视频 | 91av俱乐部| ass精品国模裸体欣赏pics | 黄色片小视频 | 日韩字幕在线观看 | 97狠狠| jizzzz中国| 成人午夜免费网站 | 日本不卡中文字幕 | 成年人的免费视频 | 四色成人网 | 日本特级黄色录像 | 狂野欧美性猛交blacked | 国产高清免费 | 久久精品一 | 日韩国产区| 美女黄色在线观看 | 久草视频免费看 | 精精国产xxxx视频在线 | 国产一区二区精彩视频 | 无码少妇一区二区三区芒果 | 色噜噜综合| 久久免费视频2 | xxxxx在线| 久久精品aⅴ无码中文字字幕重口 | 成人在线观看一区二区 | 午夜天堂av | 91av在| 精品欧美一区二区三区久久久 | 少妇把腿扒开让我舔18 | 日韩欧美亚洲国产精品字幕久久久 | 亚洲视频在线观看网址 | 精品无码久久久久久久久久 | 一区二区福利 | 日韩一区二区精品视频 | 操操干 | 亚洲综合涩| 成人免费在线小视频 | 30一40一50老女人毛片 |