自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

看一遍就理解:IO模型詳解

開(kāi)發(fā) 前端
什么是IO呢?什么是阻塞非阻塞IO?什么是同步異步IO?什么是IO多路復(fù)用?select/epoll跟IO模型有什么關(guān)系?有幾種經(jīng)典IO模型呢?BIO、NIO、AIO到底有什么區(qū)別的?

前言

大家好,我是程序員田螺。今天我們一起來(lái)學(xué)習(xí)IO模型。在本文開(kāi)始前呢,先問(wèn)問(wèn)大家?guī)讉€(gè)問(wèn)題哈~

什么是IO呢?什么是阻塞非阻塞IO?什么是同步異步IO?什么是IO多路復(fù)用?select/epoll跟IO模型有什么關(guān)系?有幾種經(jīng)典IO模型呢?BIO、NIO、AIO到底有什么區(qū)別的?

如果這些問(wèn)題,你都能很好答上的話,那恭喜你,你對(duì)IO的掌握已經(jīng)很棒啦!那你跟田螺哥一起看完這篇文章,再?gòu)?fù)習(xí)一下,加深印象吧~如果你對(duì)這些問(wèn)題模棱兩可的話,那也沒(méi)關(guān)系,看完這篇文章,就理解啦!

圖片圖片

什么是IO呢?

IO,英文全稱是Input/Output,翻譯過(guò)來(lái)就是輸入/輸出。平時(shí)我們聽(tīng)得挺多,就是什么磁盤IO,網(wǎng)絡(luò)IO。那IO到底是什么呢?是不是有種懵懵懂懂的感覺(jué)呀,好像大概知道它是什么,又好像說(shuō)不清楚。

IO,即輸入/輸出,到底誰(shuí)是輸入?誰(shuí)是輸出呢?IO如果脫離了主體,就會(huì)讓人疑惑。

計(jì)算機(jī)角度的IO

我們常說(shuō)的輸入輸出,比較直觀的意思就是計(jì)算機(jī)的輸入輸出,計(jì)算機(jī)就是主體。大家是否還記得,大學(xué)學(xué)計(jì)算機(jī)組成原理的時(shí)候,有個(gè)馮.諾依曼結(jié)構(gòu),它將計(jì)算機(jī)分成分為5個(gè)部分:運(yùn)算器、控制器、存儲(chǔ)器、輸入設(shè)備、輸出設(shè)備。

圖片圖片

輸入設(shè)備是向計(jì)算機(jī)輸入數(shù)據(jù)和信息的設(shè)備,鍵盤,鼠標(biāo)都屬于輸入設(shè)備;輸出設(shè)備是計(jì)算機(jī)硬件系統(tǒng)的終端設(shè)備,用于接收計(jì)算機(jī)數(shù)據(jù)的輸出顯示,一般顯示器、打印機(jī)屬于輸出設(shè)備。

例如你在鼠標(biāo)鍵盤敲幾下,它就會(huì)把你的指令數(shù)據(jù),傳給主機(jī),主機(jī)通過(guò)運(yùn)算后,把返回的數(shù)據(jù)信息,輸出到顯示器。

鼠標(biāo)、顯示器這只是直觀表面的輸入輸出,回到計(jì)算機(jī)架構(gòu)來(lái)說(shuō),涉及計(jì)算機(jī)核心與其他設(shè)備間數(shù)據(jù)遷移的過(guò)程,就是IO。如磁盤IO,就是從磁盤讀取數(shù)據(jù)到內(nèi)存,這算一次輸入,對(duì)應(yīng)的,將內(nèi)存中的數(shù)據(jù)寫入磁盤,就算輸出。這就是IO的本質(zhì)。

操作系統(tǒng)的IO

我們要將內(nèi)存中的數(shù)據(jù)寫入到磁盤的話,主體會(huì)是什么呢?主體可能是一個(gè)應(yīng)用程序,比如一個(gè)Java進(jìn)程(假設(shè)網(wǎng)絡(luò)傳來(lái)二進(jìn)制流,一個(gè)Java進(jìn)程可以把它寫入到磁盤)。

操作系統(tǒng)負(fù)責(zé)計(jì)算機(jī)的資源管理和進(jìn)程的調(diào)度。我們電腦上跑著的應(yīng)用程序,其實(shí)是需要經(jīng)過(guò)操作系統(tǒng),才能做一些特殊操作,如磁盤文件讀寫、內(nèi)存的讀寫等等。因?yàn)檫@些都是比較危險(xiǎn)的操作,不可以由應(yīng)用程序亂來(lái),只能交給底層操作系統(tǒng)來(lái)。也就是說(shuō),你的應(yīng)用程序要把數(shù)據(jù)寫入磁盤,只能通過(guò)調(diào)用操作系統(tǒng)開(kāi)放出來(lái)的API來(lái)操作。

  • 什么是用戶空間?什么是內(nèi)核空間?
  • 以32位操作系統(tǒng)為例,它為每一個(gè)進(jìn)程都分配了4G(2的32次方)的內(nèi)存空間。這4G可訪問(wèn)的內(nèi)存空間分為二部分,一部分是用戶空間,一部分是內(nèi)核空間。內(nèi)核空間是操作系統(tǒng)內(nèi)核訪問(wèn)的區(qū)域,是受保護(hù)的內(nèi)存空間,而用戶空間是用戶應(yīng)用程序訪問(wèn)的內(nèi)存區(qū)域。

我們應(yīng)用程序是跑在用戶空間的,它不存在實(shí)質(zhì)的IO過(guò)程,真正的IO是在操作系統(tǒng)執(zhí)行的。即應(yīng)用程序的IO操作分為兩種動(dòng)作:IO調(diào)用和IO執(zhí)行。IO調(diào)用是由進(jìn)程(應(yīng)用程序的運(yùn)行態(tài))發(fā)起,而IO執(zhí)行是操作系統(tǒng)內(nèi)核的工作。此時(shí)所說(shuō)的IO是應(yīng)用程序?qū)Σ僮飨到y(tǒng)IO功能的一次觸發(fā),即IO調(diào)用。

操作系統(tǒng)的一次IO過(guò)程

應(yīng)用程序發(fā)起的一次IO操作包含兩個(gè)階段:

  • IO調(diào)用:應(yīng)用程序進(jìn)程向操作系統(tǒng)內(nèi)核發(fā)起調(diào)用。
  • IO執(zhí)行:操作系統(tǒng)內(nèi)核完成IO操作。

操作系統(tǒng)內(nèi)核完成IO操作還包括兩個(gè)過(guò)程:

  • 準(zhǔn)備數(shù)據(jù)階段:內(nèi)核等待I/O設(shè)備準(zhǔn)備好數(shù)據(jù)
  • 拷貝數(shù)據(jù)階段:將數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到用戶進(jìn)程緩沖區(qū)

圖片圖片

其實(shí)IO就是把進(jìn)程的內(nèi)部數(shù)據(jù)轉(zhuǎn)移到外部設(shè)備,或者把外部設(shè)備的數(shù)據(jù)遷移到進(jìn)程內(nèi)部。外部設(shè)備一般指硬盤、socket通訊的網(wǎng)卡。一個(gè)完整的IO過(guò)程包括以下幾個(gè)步驟:

  • 應(yīng)用程序進(jìn)程向操作系統(tǒng)發(fā)起IO調(diào)用請(qǐng)求
  • 操作系統(tǒng)準(zhǔn)備數(shù)據(jù),把IO外部設(shè)備的數(shù)據(jù),加載到內(nèi)核緩沖區(qū)
  • 操作系統(tǒng)拷貝數(shù)據(jù),即將內(nèi)核緩沖區(qū)的數(shù)據(jù),拷貝到用戶進(jìn)程緩沖區(qū)

阻塞IO模型

我們已經(jīng)知道IO是什么啦,那什么是阻塞IO呢?

假設(shè)應(yīng)用程序的進(jìn)程發(fā)起IO調(diào)用,但是如果內(nèi)核的數(shù)據(jù)還沒(méi)準(zhǔn)備好的話,那應(yīng)用程序進(jìn)程就一直在阻塞等待,一直等到內(nèi)核數(shù)據(jù)準(zhǔn)備好了,從內(nèi)核拷貝到用戶空間,才返回成功提示,此次IO操作,稱之為阻塞IO。

圖片圖片

  • 阻塞IO比較經(jīng)典的應(yīng)用就是阻塞socket、Java BIO。
  • 阻塞IO的缺點(diǎn)就是:如果內(nèi)核數(shù)據(jù)一直沒(méi)準(zhǔn)備好,那用戶進(jìn)程將一直阻塞,浪費(fèi)性能,可以使用非阻塞IO優(yōu)化。

非阻塞IO模型

如果內(nèi)核數(shù)據(jù)還沒(méi)準(zhǔn)備好,可以先返回錯(cuò)誤信息給用戶進(jìn)程,讓它不需要等待,而是通過(guò)輪詢的方式再來(lái)請(qǐng)求。這就是非阻塞IO,流程圖如下:

圖片圖片

非阻塞IO的流程如下:

  • 應(yīng)用進(jìn)程向操作系統(tǒng)內(nèi)核,發(fā)起recvfrom讀取數(shù)據(jù)。
  • 操作系統(tǒng)內(nèi)核數(shù)據(jù)沒(méi)有準(zhǔn)備好,立即返回EWOULDBLOCK錯(cuò)誤碼。
  • 應(yīng)用程序進(jìn)程輪詢調(diào)用,繼續(xù)向操作系統(tǒng)內(nèi)核發(fā)起recvfrom讀取數(shù)據(jù)。
  • 操作系統(tǒng)內(nèi)核數(shù)據(jù)準(zhǔn)備好了,從內(nèi)核緩沖區(qū)拷貝到用戶空間。
  • 完成調(diào)用,返回成功提示。

非阻塞IO模型,簡(jiǎn)稱NIO,Non-Blocking IO。它相對(duì)于阻塞IO,雖然大幅提升了性能,但是它依然存在性能問(wèn)題,即頻繁的輪詢,導(dǎo)致頻繁的系統(tǒng)調(diào)用,同樣會(huì)消耗大量的CPU資源??梢钥紤]IO復(fù)用模型,去解決這個(gè)問(wèn)題。

IO多路復(fù)用模型

既然NIO無(wú)效的輪詢會(huì)導(dǎo)致CPU資源消耗,我們等到內(nèi)核數(shù)據(jù)準(zhǔn)備好了,主動(dòng)通知應(yīng)用進(jìn)程再去進(jìn)行系統(tǒng)調(diào)用,那不就好了嘛?

在這之前,我們先來(lái)復(fù)習(xí)下,什么是文件描述符fd(File Descriptor),它是計(jì)算機(jī)科學(xué)中的一個(gè)術(shù)語(yǔ),形式上是一個(gè)非負(fù)整數(shù)。當(dāng)程序打開(kāi)一個(gè)現(xiàn)有文件或者創(chuàng)建一個(gè)新文件時(shí),內(nèi)核向進(jìn)程返回一個(gè)文件描述符。

IO復(fù)用模型核心思路:系統(tǒng)給我們提供一類函數(shù)(如我們耳濡目染的select、poll、epoll函數(shù)),它們可以同時(shí)監(jiān)控多個(gè)fd的操作,任何一個(gè)返回內(nèi)核數(shù)據(jù)就緒,應(yīng)用進(jìn)程再發(fā)起recvfrom系統(tǒng)調(diào)用。

IO多路復(fù)用之select

應(yīng)用進(jìn)程通過(guò)調(diào)用select函數(shù),可以同時(shí)監(jiān)控多個(gè)fd,在select函數(shù)監(jiān)控的fd中,只要有任何一個(gè)數(shù)據(jù)狀態(tài)準(zhǔn)備就緒了,select函數(shù)就會(huì)返回可讀狀態(tài),這時(shí)應(yīng)用進(jìn)程再發(fā)起recvfrom請(qǐng)求去讀取數(shù)據(jù)。

圖片圖片

非阻塞IO模型(NIO)中,需要N(N>=1)次輪詢系統(tǒng)調(diào)用,然而借助select的IO多路復(fù)用模型,只需要發(fā)起一次詢問(wèn)就夠了,大大優(yōu)化了性能。

但是呢,select有幾個(gè)缺點(diǎn):

  • 監(jiān)聽(tīng)的IO最大連接數(shù)有限,在Linux系統(tǒng)上一般為1024。
  • select函數(shù)返回后,是通過(guò)遍歷fdset,找到就緒的描述符fd。(僅知道有I/O事件發(fā)生,卻不知是哪幾個(gè)流,所以遍歷所有流)

因?yàn)榇嬖谶B接數(shù)限制,所以后來(lái)又提出了poll。與select相比,poll解決了連接數(shù)限制問(wèn)題。但是呢,select和poll一樣,還是需要通過(guò)遍歷文件描述符來(lái)獲取已經(jīng)就緒的socket。如果同時(shí)連接的大量客戶端,在一時(shí)刻可能只有極少處于就緒狀態(tài),伴隨著監(jiān)視的描述符數(shù)量的增長(zhǎng),效率也會(huì)線性下降。

因此經(jīng)典的多路復(fù)用模型epoll誕生。

IO多路復(fù)用之epoll

為了解決select/poll存在的問(wèn)題,多路復(fù)用模型epoll誕生,它采用事件驅(qū)動(dòng)來(lái)實(shí)現(xiàn),流程圖如下:

圖片圖片

epoll先通過(guò)epoll_ctl()來(lái)注冊(cè)一個(gè)fd(文件描述符),一旦基于某個(gè)fd就緒時(shí),內(nèi)核會(huì)采用回調(diào)機(jī)制,迅速激活這個(gè)fd,當(dāng)進(jìn)程調(diào)用epoll_wait()時(shí)便得到通知。這里去掉了遍歷文件描述符的坑爹操作,而是采用監(jiān)聽(tīng)事件回調(diào)的機(jī)制。這就是epoll的亮點(diǎn)。

我們一起來(lái)總結(jié)一下select、poll、epoll的區(qū)別


select

poll

epoll

底層數(shù)據(jù)結(jié)構(gòu)

數(shù)組

鏈表

紅黑樹(shù)和雙鏈表

獲取就緒的fd

遍歷

遍歷

事件回調(diào)

事件復(fù)雜度

O(n)

O(n)

O(1)

最大連接數(shù)

1024

無(wú)限制

無(wú)限制

fd數(shù)據(jù)拷貝

每次調(diào)用select,需要將fd數(shù)據(jù)從用戶空間拷貝到內(nèi)核空間

每次調(diào)用poll,需要將fd數(shù)據(jù)從用戶空間拷貝到內(nèi)核空間

使用內(nèi)存映射(mmap),不需要從用戶空間頻繁拷貝fd數(shù)據(jù)到內(nèi)核空間

epoll明顯優(yōu)化了IO的執(zhí)行效率,但在進(jìn)程調(diào)用epoll_wait()時(shí),仍然可能被阻塞。能不能醬紫:不用我老是去問(wèn)你數(shù)據(jù)是否準(zhǔn)備就緒,等我發(fā)出請(qǐng)求后,你數(shù)據(jù)準(zhǔn)備好了通知我就行了,這就誕生了信號(hào)驅(qū)動(dòng)IO模型。

IO模型之信號(hào)驅(qū)動(dòng)模型

信號(hào)驅(qū)動(dòng)IO不再用主動(dòng)詢問(wèn)的方式去確認(rèn)數(shù)據(jù)是否就緒,而是向內(nèi)核發(fā)送一個(gè)信號(hào)(調(diào)用sigaction的時(shí)候建立一個(gè)SIGIO的信號(hào)),然后應(yīng)用用戶進(jìn)程可以去做別的事,不用阻塞。當(dāng)內(nèi)核數(shù)據(jù)準(zhǔn)備好后,再通過(guò)SIGIO信號(hào)通知應(yīng)用進(jìn)程,數(shù)據(jù)準(zhǔn)備好后的可讀狀態(tài)。應(yīng)用用戶進(jìn)程收到信號(hào)之后,立即調(diào)用recvfrom,去讀取數(shù)據(jù)。

圖片圖片

信號(hào)驅(qū)動(dòng)IO模型,在應(yīng)用進(jìn)程發(fā)出信號(hào)后,是立即返回的,不會(huì)阻塞進(jìn)程。它已經(jīng)有異步操作的感覺(jué)了。但是你細(xì)看上面的流程圖,發(fā)現(xiàn)數(shù)據(jù)復(fù)制到應(yīng)用緩沖的時(shí)候,應(yīng)用進(jìn)程還是阻塞的?;剡^(guò)頭來(lái)看下,不管是BIO,還是NIO,還是信號(hào)驅(qū)動(dòng),在數(shù)據(jù)從內(nèi)核復(fù)制到應(yīng)用緩沖的時(shí)候,都是阻塞的。還有沒(méi)有優(yōu)化方案呢?AIO(真正的異步IO)!

IO 模型之異步IO(AIO)

前面講的BIO,NIO和信號(hào)驅(qū)動(dòng),在數(shù)據(jù)從內(nèi)核復(fù)制到應(yīng)用緩沖的時(shí)候,都是阻塞的,因此都不算是真正的異步。AIO實(shí)現(xiàn)了IO全流程的非阻塞,就是應(yīng)用進(jìn)程發(fā)出系統(tǒng)調(diào)用后,是立即返回的,但是立即返回的不是處理結(jié)果,而是表示提交成功類似的意思。等內(nèi)核數(shù)據(jù)準(zhǔn)備好,將數(shù)據(jù)拷貝到用戶進(jìn)程緩沖區(qū),發(fā)送信號(hào)通知用戶進(jìn)程IO操作執(zhí)行完畢。

流程如下:

圖片圖片

異步IO的優(yōu)化思路很簡(jiǎn)單,只需要向內(nèi)核發(fā)送一次請(qǐng)求,就可以完成數(shù)據(jù)狀態(tài)詢問(wèn)和數(shù)據(jù)拷貝的所有操作,并且不用阻塞等待結(jié)果。日常開(kāi)發(fā)中,有類似思想的業(yè)務(wù)場(chǎng)景:

比如發(fā)起一筆批量轉(zhuǎn)賬,但是批量轉(zhuǎn)賬處理比較耗時(shí),這時(shí)候后端可以先告知前端轉(zhuǎn)賬提交成功,等到結(jié)果處理完,再通知前端結(jié)果即可。

阻塞、非阻塞、同步、異步IO劃分

圖片圖片

IO模型


阻塞I/O模型

同步阻塞

非阻塞I/O模型

同步非阻塞

I/O多路復(fù)用模型

同步阻塞

信號(hào)驅(qū)動(dòng)I/O模型

同步非阻塞

異步IO(AIO)模型

異步非阻塞

一個(gè)通俗例子讀懂BIO、NIO、AIO

  • 同步阻塞(blocking-IO)簡(jiǎn)稱BIO
  • 同步非阻塞(non-blocking-IO)簡(jiǎn)稱NIO
  • 異步非阻塞(asynchronous-non-blocking-IO)簡(jiǎn)稱AIO

一個(gè)經(jīng)典生活的例子:

  • 小明去吃同仁四季的椰子雞,就這樣在那里排隊(duì),等了一小時(shí),然后才開(kāi)始吃火鍋。(BIO)
  • 小紅也去同仁四季的椰子雞,她一看要等挺久的,于是去逛會(huì)商場(chǎng),每次逛一下,就跑回來(lái)看看,是不是輪到她了。于是最后她既購(gòu)了物,又吃上椰子雞了。(NIO)
  • 小華一樣,去吃椰子雞,由于他是高級(jí)會(huì)員,所以店長(zhǎng)說(shuō),你去商場(chǎng)隨便逛會(huì)吧,等下有位置,我立馬打電話給你。于是小華不用干巴巴坐著等,也不用每過(guò)一會(huì)兒就跑回來(lái)看有沒(méi)有等到,最后也吃上了美味的椰子雞(AIO)
責(zé)任編輯:武曉燕 來(lái)源: 撿田螺的小男孩
相關(guān)推薦

2021-12-01 07:26:13

IO模型異步

2021-06-15 07:15:15

Oracle底層explain

2022-01-17 20:59:37

開(kāi)發(fā)group by思路

2021-08-12 10:36:18

order byMySQL數(shù)據(jù)庫(kù)

2025-02-13 09:06:27

2021-10-07 20:12:03

MVCC事務(wù)原理

2024-03-12 08:20:57

零拷貝存儲(chǔ)開(kāi)發(fā)

2020-02-09 17:30:54

反轉(zhuǎn)鏈表程序員節(jié)點(diǎn)

2019-03-19 14:11:44

VLANLANMAC

2022-05-08 23:05:38

Route-Poli路由策略

2023-09-12 07:31:45

HashMap線程

2022-08-26 10:41:03

指針C語(yǔ)言

2019-09-19 08:04:40

網(wǎng)絡(luò)七層模型TCPUDP

2021-10-08 07:53:01

事務(wù)隔離級(jí)別

2023-08-14 07:49:42

AI訓(xùn)練

2017-12-26 14:17:24

潤(rùn)乾報(bào)表

2023-01-10 19:47:47

Redis原理多線程

2021-11-25 08:16:46

Wi-FiWi-Fi 6路由Wi-Fi 5

2015-10-10 11:10:24

重敲代碼拷貝粘貼

2021-03-11 07:14:01

Epoll原理線程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)