IO模式總結(jié)

網(wǎng)上看了好多IO,NIO的文字,參差不齊,每篇總是差一兩個(gè)點(diǎn)沒(méi)有講到,所以這里對(duì)于我自己理解的做一個(gè)總結(jié),也許有不對(duì)的地方。

1,基本概念

1.1)同步/異步,阻塞/非阻塞

同步異步主要針對(duì)C端:

所謂同步,就是在c端發(fā)出一個(gè)功能調(diào)用時(shí),在沒(méi)有得到結(jié)果之前,該調(diào)用就不返回。也就是必須一件一件事做,等前一件做完了才能做下一件事。

異步的概念和同步相對(duì)。當(dāng)c端一個(gè)異步過(guò)程調(diào)用發(fā)出后,調(diào)用者不能立刻得到結(jié)果。實(shí)際處理這個(gè)調(diào)用的部件在完成后,通過(guò)狀態(tài)、通知和回調(diào)來(lái)通知調(diào)用者。

阻塞非阻塞主要針對(duì)S端:

阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起(線程進(jìn)入非可執(zhí)行狀態(tài),在這個(gè)狀態(tài)下,cpu不會(huì)給線程分配時(shí)間片,即線程暫停運(yùn)行)。函數(shù)只有在得到結(jié)果之后才會(huì)返回。

非阻塞和阻塞的概念相對(duì)應(yīng),指在不能立刻得到結(jié)果之前,該函數(shù)不會(huì)阻塞當(dāng)前線程,而會(huì)立刻返回。

1.2)面向流,面向緩沖區(qū)

面向流:每次從流中讀一個(gè)或多個(gè)字節(jié),直至讀取所有字節(jié),它們沒(méi)有被緩存在任何地方。

面向緩沖區(qū):數(shù)據(jù)讀取到一個(gè)它稍后處理的緩沖區(qū),需要時(shí)可在緩沖區(qū)中前后移動(dòng)。這就增加了處理過(guò)程中的靈活性。

1.4)內(nèi)核態(tài)和用戶態(tài)

內(nèi)核空間可以訪問(wèn)受保護(hù)的內(nèi)存(32位下高位1G為內(nèi)核空間),剩下3G為用戶空間

操作系統(tǒng)限制用戶態(tài)不能直接訪問(wèn)硬件設(shè)備,所以數(shù)據(jù)從硬件移動(dòng)到用戶進(jìn)程的內(nèi)存時(shí)需要2步操作。

image.png

1.3)mmap(內(nèi)存映射)

將一個(gè)文件或者其它對(duì)象映射到進(jìn)程的地址空間,實(shí)現(xiàn)文件磁盤地址和進(jìn)程虛擬地址空間中一段虛擬地址的一一對(duì)映關(guān)系


image.png
image2.png

2,linux下的5種IO模型

ea103750d79f9799947fdb5a99da11fb.jpg

5種IO模式關(guān)于同步異步,阻塞非阻塞的關(guān)系

阻塞 非阻塞
同步 BIO nonblockingIO/多路復(fù)用IO(NIO1.0)
異步 X AIO
1,BIO:

阻塞當(dāng)前線程,等待數(shù)據(jù)準(zhǔn)備

image.png

2,nonblockingIO:

image.png

相當(dāng)于輪訓(xùn),將大片的等待時(shí)間切割成小片,

3,多路復(fù)用IO(IO mulitplexing)NIO

監(jiān)聽多個(gè)socket,當(dāng)任何一個(gè)數(shù)據(jù)準(zhǔn)備好后就返回,用戶進(jìn)程再調(diào)用read函數(shù)讀取數(shù)據(jù),極限情況,如果只監(jiān)聽一個(gè)socket那么和BIO是一樣的,只有監(jiān)聽的socket多時(shí),才會(huì)凸顯效率。

重點(diǎn),后面詳細(xì)說(shuō)明

image2.png

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

5, asynchronous IO

需要操作系統(tǒng)內(nèi)核支持

image.png

aio目前在linux下存在BUG,使用場(chǎng)景少

3,為什么說(shuō)JAVA的標(biāo)準(zhǔn)IO是面向流,NIO面向緩沖區(qū)

標(biāo)準(zhǔn)IO:

SocketInputStream.read

int read(byte b[], int off, int length, int timeout) throws IOException {

int n;

// EOF already encountered

if (eof) {

return -1;

}

// connection reset

if (impl.isConnectionReset()) {

throw new SocketException("Connection reset");

}

// bounds check

if (length <= 0 || off < 0 || off + length > b.length) {

if (length == 0) {

return 0;

}

throw new ArrayIndexOutOfBoundsException();

}

boolean gotReset = false;

// acquire file descriptor and do the read

FileDescriptor fd = impl.acquireFD();

try {

n = socketRead(fd, b, off, length, timeout);//native函數(shù)

if (n > 0) {

return n;

}

} catch (ConnectionResetException rstExc) {

gotReset = true;

} finally {

impl.releaseFD();

}

/*

* We receive a "connection reset" but there may be bytes still

* buffered on the socket

*/

if (gotReset) {

impl.setConnectionResetPending();

impl.acquireFD();

try {

n = socketRead(fd, b, off, length, timeout);//native函數(shù),這里從內(nèi)核態(tài)中讀取數(shù)據(jù)到數(shù)組b中

if (n > 0) {

return n;

}

} catch (ConnectionResetException rstExc) {

} finally {

impl.releaseFD();

}

}

/*

* If we get here we are at EOF, the socket has been closed,

* or the connection has been reset.

*/

if (impl.isClosedOrPending()) {

throw new SocketException("Socket closed");

}

if (impl.isConnectionResetPending()) {

impl.setConnectionReset();

}

if (impl.isConnectionReset()) {

throw new SocketException("Connection reset");

}

eof = true;

return -1;

}

面向緩沖區(qū)(NIO):

DatagramChannelImpl.receive

private int receive(FileDescriptor fd, ByteBuffer dst)

throws IOException

{

int pos = dst.position();

int lim = dst.limit();

assert (pos <= lim);

int rem = (pos <= lim ? lim - pos : 0);

if (dst instanceof DirectBuffer && rem > 0)

return receiveIntoNativeBuffer(fd, dst, rem, pos);

// Substitute a native buffer. If the supplied buffer is empty

// we must instead use a nonempty buffer, otherwise the call

// will not block waiting for a datagram on some platforms.

int newSize = Math.max(rem, 1);

ByteBuffer bb = Util.getTemporaryDirectBuffer(newSize);//申請(qǐng)一塊newSize大小的緩沖區(qū)塊

try {

int n = receiveIntoNativeBuffer(fd, bb, newSize, 0);//數(shù)據(jù)讀取到緩沖區(qū)中,buffer可以做標(biāo)記,操作指針等

bb.flip();

if (n > 0 && rem > 0)

dst.put(bb);

return n;

} finally {

Util.releaseTemporaryDirectBuffer(bb);

}

}

channel buffer 說(shuō)明:

http://www.itdecent.cn/p/052035037297

4,select,poll,epoll詳解

select

int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

監(jiān)視所有的readFD,writeFD,exceptFD

select的一 個(gè)缺點(diǎn)在于單個(gè)進(jìn)程能夠監(jiān)視的文件描述符的數(shù)量存在最大限制

poll

int poll (struct pollfd *fds, unsigned int nfds, int timeout);

pollfd并沒(méi)有最大數(shù)量限制

select和poll沒(méi)有太大區(qū)別,都是輪訓(xùn)所有的fd/pollfd來(lái)獲取準(zhǔn)備好的fd,當(dāng)有大量連接的客戶端時(shí),效率會(huì)線性下降

epoll

1)int epfd = epoll_create(intsize); 創(chuàng)建一個(gè)ep句柄(/proc/進(jìn)程id/fd/),用于監(jiān)聽所有注冊(cè)的套接字,存在一個(gè)紅黑樹的數(shù)據(jù)結(jié)構(gòu)中,這棵紅黑樹的存儲(chǔ)通過(guò)mmap將內(nèi)核態(tài)和用戶態(tài)共享,減少用戶態(tài)和內(nèi)核態(tài)之間的數(shù)據(jù)交換,而select/poll每次輪訓(xùn)時(shí)都要將相關(guān)的句柄從內(nèi)核態(tài)拷貝至用戶態(tài)。

2)int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) 添加/修改/刪除注冊(cè)的套接字,由于是在紅黑樹中,效率較高,當(dāng)事件添加時(shí),該事件會(huì)與相應(yīng)的設(shè)備(網(wǎng)卡)驅(qū)動(dòng)程序建立回調(diào)連接,一旦事件發(fā)生(文件fd改變)相應(yīng)fd會(huì)回調(diào)這個(gè)函數(shù),將事件添加到一個(gè)rdllist(雙向鏈表)中

事件類型:

EPOLLIN :表示對(duì)應(yīng)的文件描述符可以讀(包括對(duì)端SOCKET正常關(guān)閉); EPOLLOUT:表示對(duì)應(yīng)的文件描述符可以寫; EPOLLPRI:表示對(duì)應(yīng)的文件描述符有緊急的數(shù)據(jù)可讀(這里應(yīng)該表示有帶外數(shù)據(jù)到來(lái)); EPOLLERR:表示對(duì)應(yīng)的文件描述符發(fā)生錯(cuò)誤; EPOLLHUP:表示對(duì)應(yīng)的文件描述符被掛斷;

3)int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)

3.1)調(diào)用ep_poll,當(dāng)rdllist為空時(shí)掛起,一直到rdllist不為空時(shí)喚醒

3.2)ep_events_transfer函數(shù)將rdlist中的epitem拷貝到txlist中,并將rdlist清空。ep_send_events函數(shù)(很關(guān)鍵),它掃描txlist中的每個(gè)epitem,調(diào)用其關(guān)聯(lián)fd對(duì)用的poll方法。此時(shí)對(duì)poll的調(diào)用僅僅是取得fd上較新的events(防止之前events被更新),之后將取得的events和相應(yīng)的fd發(fā)送到用戶空間(封裝在struct epoll_event,從epoll_wait返回)。

epoll.jpg

3,asynchronous IO

IO詳解:https://segmentfault.com/a/1190000003063859#articleHeader14

select、poll、epoll之間的區(qū)別總結(jié)[整理]http://www.cnblogs.com/Anker/p/3265058.html

http://www.cnblogs.com/lojunren/p/3856290.html

http://www.smithfox.com/?e=191

這篇對(duì)IO流操作寫的比較好 http://www.cnblogs.com/hapjin/p/5736188.html

補(bǔ)充:

創(chuàng)建Selectorprovider

當(dāng)linux內(nèi)核>2.6時(shí)使用epoll

public static SelectorProvider create() {

String osname = AccessController.doPrivileged(

new GetPropertyAction("os.name"));

if ("SunOS".equals(osname)) {

return new sun.nio.ch.DevPollSelectorProvider();

}

// use EPollSelectorProvider for Linux kernels >= 2.6

if ("Linux".equals(osname)) {

String osversion = AccessController.doPrivileged(

new GetPropertyAction("os.version"));

String[] vers = osversion.split("\\.", 0);

if (vers.length >= 2) {

try {

int major = Integer.parseInt(vers[0]);

int minor = Integer.parseInt(vers[1]);

if (major > 2 || (major == 2 && minor >= 6)) {

return new sun.nio.ch.EPollSelectorProvider();

}

} catch (NumberFormatException x) {

// format not recognized

}

}

}

return new sun.nio.ch.PollSelectorProvider();

}

select poll模式

int poll ( struct pollfd * fds, unsigned int nfds, int timeout);

通過(guò)程序去控制傳入的監(jiān)控fd

代碼層面監(jiān)視多個(gè)描述符,描述文件越多越慢

nio selector:

http://www.itdecent.cn/p/0d497fe5484a

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 同步IO和異步IO,阻塞IO和非阻塞IO分別是什么,到底有什么區(qū)別?不同的人在不同的上下文下給出的答案是不同的。所...
    Daniel521閱讀 1,463評(píng)論 0 6
  • IO模型介紹 為了更好地了解IO模型,我們需要事先回顧下:同步、異步、阻塞、非阻塞 同步(synchronous)...
    可笑的黑耀斑閱讀 1,327評(píng)論 0 2
  • 同步IO和異步IO,阻塞IO和非阻塞IO分別是什么,到底有什么區(qū)別?不同的人在不同的上下文下給出的答案是不同的。所...
    lxqfirst閱讀 2,223評(píng)論 0 47
  • 必備的理論基礎(chǔ) 1.操作系統(tǒng)作用: 隱藏丑陋復(fù)雜的硬件接口,提供良好的抽象接口。 管理調(diào)度進(jìn)程,并將多個(gè)進(jìn)程對(duì)硬件...
    drfung閱讀 3,762評(píng)論 0 5
  • python之路——IO模型 IO模型介紹 為了更好地了解IO模型,我們需要事先回顧下:同步、異步、阻塞、非阻塞 ...
    go以恒閱讀 596評(píng)論 0 2

友情鏈接更多精彩內(nèi)容