五種IO模型
關(guān)鍵詞:
pollepollselectchannelInputoutputAIOBIONIO多路復(fù)用多線程進(jìn)程用戶態(tài)內(nèi)核態(tài)字節(jié)流字符流
IO種類(lèi)分為: 阻塞IO,非阻塞IO,IO多路復(fù)用,信號(hào)驅(qū)動(dòng)IO,異步IO 共5種
IO 全程 Input/Output,針對(duì)不同的數(shù)據(jù)存儲(chǔ)媒介,大致可以分為網(wǎng)絡(luò) IO 和磁盤(pán) IO 兩種。一個(gè)完整的 IO 操作將經(jīng)歷一下兩個(gè)階段:用戶空間 <-> 內(nèi)核空間 <-> 設(shè)備空間
。
IO具體是什么操作?
干了什么事?
為什么有5種類(lèi)型?
5種類(lèi)型分別解決了什么問(wèn)題?
只用阻塞IO可以嗎?
IO牽扯到具體的指令有哪些?
IO讀操作
真正的IO讀操作:外部設(shè)備的數(shù)據(jù)經(jīng)過(guò)總線進(jìn)入RAM中系統(tǒng)空間的系統(tǒng)緩沖區(qū)。
用戶看到的假I(mǎi)O操作:用戶調(diào)用IO接口函數(shù),從系統(tǒng)緩沖區(qū)讀取數(shù)據(jù)讀到自己的緩沖區(qū)或某個(gè)變量中
IO寫(xiě)操作
真正的IO寫(xiě)操作:RAM中系統(tǒng)空間的系統(tǒng)緩沖區(qū)中的數(shù)據(jù)經(jīng)過(guò)總線進(jìn)入外部設(shè)備。
用戶看到的假I(mǎi)O操作:用戶調(diào)用IO接口函數(shù),把自己的某個(gè)變量或者自己的緩沖區(qū)寫(xiě)入系統(tǒng)緩沖區(qū)。
實(shí)際IO過(guò)程
用戶調(diào)用IO接口函數(shù)后會(huì)詢問(wèn)內(nèi)核緩沖區(qū)是否有目標(biāo)數(shù)據(jù),如果沒(méi)有內(nèi)核緩沖區(qū)在外部設(shè)備準(zhǔn)備好后接收IO接口傳來(lái)的數(shù)據(jù),內(nèi)核緩沖區(qū)讀取外部設(shè)備的數(shù)據(jù)的過(guò)程是IO過(guò)程。
阻塞IO:
需要等待內(nèi)核 IO 操作徹底完成后才返回到用戶空間的 IO 操作。在 IO 操作過(guò)程中,發(fā)起 IO 請(qǐng)求的用戶進(jìn)程處于阻塞狀態(tài)。
模型如下:

同步非阻塞IO
不需要等待內(nèi)核 IO 操作徹底完成就能立即返回用戶空間的 IO 操作。在 IO 操作過(guò)程中,發(fā)起 IO 請(qǐng)求的用戶進(jìn)程處于非阻塞狀態(tài)。
模型:

IO多路復(fù)用
解決了 NIO 中的頻繁輪詢 CPU 的問(wèn)題,并且引入一種新的 select 系統(tǒng)調(diào)用。
復(fù)用 IO 的基本思路就是通過(guò) slect 調(diào)用來(lái)監(jiān)控多 fd(文件描述符),來(lái)達(dá)到不必為每個(gè) fd 創(chuàng)建一個(gè)對(duì)應(yīng)的監(jiān)控線程的目的,從而減少線程資源創(chuàng)建的開(kāi)銷(xiāo)。一旦某個(gè)描述符就緒(一般是內(nèi)核緩沖區(qū)可讀/可寫(xiě)),內(nèi)核就能夠?qū)⑽募枋龇木途w狀態(tài)返回給用戶進(jìn)程(或者線程),用戶空間可以根據(jù)文件描述符的就緒狀態(tài)進(jìn)行相應(yīng)的 IO 系統(tǒng)調(diào)用。
Linux中IO復(fù)用的實(shí)現(xiàn)方式主要有Select,Poll和Epoll:
Select:注冊(cè)IO、阻塞掃描,監(jiān)聽(tīng)的IO最大連接數(shù)不能多于FD_ SIZE(1024)。
Poll:原理和Select相似,沒(méi)有數(shù)量限制,但I(xiàn)O數(shù)量大,掃描線性性能下降。
Epoll :事件驅(qū)動(dòng)不阻塞,mmap實(shí)現(xiàn)內(nèi)核與用戶空間的消息傳遞,數(shù)量很大,Linux2.6后內(nèi)核支持。
IO 多路復(fù)用(IO Multiplexing)屬于一種經(jīng)典的 Reactor 模式實(shí)現(xiàn),有時(shí)也稱(chēng)為異步阻塞 IO。
poll和epoll的區(qū)別:
在Java中,epoll和poll是用于實(shí)現(xiàn)I/O多路復(fù)用的機(jī)制,但它們?cè)诘讓訉?shí)現(xiàn)和使用方式上有一些區(qū)別。
1.poll是傳統(tǒng)的I/O多路復(fù)用機(jī)制,而epoll是Linux特有的高性能I/O多路復(fù)用機(jī)制。
2.poll使用的是輪詢方式,它通過(guò)遍歷文件描述符集合來(lái)檢查是否有事件發(fā)生,效率相對(duì)較低。
3.epoll使用的是事件通知方式,它通過(guò)注冊(cè)文件描述符和事件,并在事件發(fā)生時(shí)立即通知應(yīng)用程序,避免了不必要的輪詢,提高了效率。

信號(hào)驅(qū)動(dòng)IO
信號(hào)驅(qū)動(dòng)IO是異步阻塞IO,不需要等待IO的過(guò)程,但是從內(nèi)核讀取數(shù)據(jù)受到阻塞

異步IO
異步IO從圖上看很像信號(hào)驅(qū)動(dòng)IO,但是實(shí)際差別很大,異步IO指異步非阻塞IO。異步IO不需要建立信號(hào)處理程序,再把IO接口函數(shù)放進(jìn)去。異步IO只需要調(diào)用IO接口函數(shù),在里面加入數(shù)據(jù)處理函數(shù)即可,并且不存在任何阻塞

總結(jié):
對(duì)比:

實(shí)際的多線程模型:
根據(jù)博客參考,實(shí)際的多線程模型有很多。在《操作系統(tǒng)》中介紹較少,理解起來(lái)并不是很全面。
多對(duì)一模型:進(jìn)程下的多個(gè)用戶級(jí)線程對(duì)應(yīng)著一個(gè)核心級(jí)線程,這也就是《操作系統(tǒng)》中說(shuō)這句話的默認(rèn)情景。操作系統(tǒng)知道核心線程,不知到用戶線程,當(dāng)用戶線程阻塞時(shí)會(huì)認(rèn)為是核心級(jí)線程阻塞,那么操作系統(tǒng)會(huì)調(diào)度另一個(gè)核心級(jí)線程執(zhí)行。
一對(duì)一模型:進(jìn)程下的每個(gè)用戶級(jí)線程對(duì)應(yīng)著屬于自己的核心級(jí)線程。當(dāng)一個(gè)線程被阻塞時(shí),操作系統(tǒng)能夠讓另一個(gè)核心級(jí)線程對(duì)應(yīng)的用戶線程繼續(xù)執(zhí)行。缺點(diǎn)是每個(gè)用戶線程都會(huì)創(chuàng)建一個(gè)核心級(jí)線程,未免有些浪費(fèi)。
多對(duì)多模型:進(jìn)程下的每個(gè)用戶級(jí)線程對(duì)應(yīng)著多個(gè)核心級(jí)線程,每個(gè)核心級(jí)線程也對(duì)應(yīng)著多個(gè)用戶級(jí)線程。這個(gè)模型能完成前兩個(gè)模型能完成的任務(wù),但是實(shí)現(xiàn)復(fù)雜。
線程與進(jìn)程的區(qū)別與聯(lián)系
線程是輕量級(jí)的進(jìn)程
線程沒(méi)有獨(dú)立的地址空間(內(nèi)存空間)
線程是由進(jìn)程創(chuàng)建的(寄生在進(jìn)程)
一個(gè)進(jìn)程可以擁有多個(gè)線程(這就是我們常說(shuō)的多線程編程)