I/O模型
Linux 下的五种I/O模型
- 阻塞I/O(blocking I/O)
- 非阻塞I/O (nonblocking I/O)
- I/O复用(select 和poll) (I/O multiplexing)
- 信号驱动I/O (signal driven I/O (SIGIO))
- 异步I/O (asynchronous I/O (the POSIX aio_functions))
前四种都是同步,只有最后一种才是异步IO。
Winsock的异步IO模型有下面六种
- select选择模型
- WSAAsyncSelect 异步选择模型
- WSAEventSelect 事件选择模型
- Overlapped I/O 事件通知模型
- Overlapped I/O 完成例程模型
- IOCP模型
Linux 的几种I/O模型介绍:
阻塞I/O模型:
简介:进程会一直阻塞,直到数据拷贝完成
应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好。 如果数据没有准备好,一直等待….数据准备好了,从内核拷贝到用户空间,IO函数返回成功指示。
可能阻塞套接字的Windows Sockets API调用分为以下四种:
1.输入操作: recv()、recvfrom()、WSARecv()和WSARecvfrom()函数。以阻塞套接字为参数调用该函数接收数据。如果此时套接字缓冲区内没有数据可读,则调用线程在数据到来前一直睡眠。
2.输出操作: send()、sendto()、WSASend()和WSASendto()函数。以阻塞套接字为参数调用该函数发送数据。如果套接字缓冲区没有可用空间,线程会一直睡眠,直到有空间。
3.接受连接:accept()和WSAAcept()函数。以阻塞套接字为参数调用该函数,等待接受对方的连接请求。如果此时没有连接请求,线程就会进入睡眠状态。
4.外出连接:connect()和WSAConnect()函数。对于TCP连接,客户端以阻塞套接字为参数,调用该函数向服务器发起连接。该函数在收到服务器的应答前,不会返回。这意味着TCP连接总会等待至少到服务器的一次往返时间。
非阻塞I/O模型
简介:非阻塞IO通过进程反复调用IO函数(多次系统调用,并马上返回);在数据拷贝的过程中,进程是阻塞的;
我们把一个SOCKET接口设置为非阻塞就是告诉内核,当所请求的I/O操作无法完成时,不要将进程睡眠,而是返回一个错误。这样我们的I/O操作函数将不断的测试数据是否已经准备好,如果没有准备好,继续测试,直到数据准备好为止。在这个不断测试的过程中,会大量的占用CPU的时间。
非阻塞套接字在控制建立的多个连接,在数据的收发量不均,时间不定时,明显具有优势。这种套接字在使用上存在一定难度,但只要排除了这些困难,它在功能上还是非常强大的。
I/O复用模型
简介:主要是select和epoll;对一个IO端口,两次调用,两次返回,比阻塞IO并没有什么优越性;关键是能实现同时对多个IO端口进行监听;
I/O复用模型会用到select、poll、epoll函数,这几个函数也会使进程阻塞,但是和阻塞I/O所不同的的,这两个函数可以同时阻塞多个I/O操作。而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数。
信号驱动I/O模型
简介:两次调用,两次返回;
首先我们允许套接口进行信号驱动I/O,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。
异步I/O模型
简介:数据拷贝的时候进程无需阻塞。
当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者的输入输出操作
5种I/O模型的比较:
Windows I/O模型介绍
网上有个比喻很好的说明这些模型,在这里引用一下。
老陈有一个在外地工作的女儿,不能经常回来,老陈和她通过信件联系。他们的信会被邮递员投递到他们的信箱里。
select模型
老陈非常想看到女儿的信。以至于他每隔10分钟就下楼检查信箱,看是否有女儿的信~~~~~
在这种情况下,“下楼检查信箱”然后回到楼上耽误了老陈太多的时间,以至于老陈无法做其他工作。
WSAAsyncSelect模型
后来,老陈使用了微软公司的新式信箱。这种信箱非常先进,一旦信箱里有新的信件,盖茨就会给老陈打电话:喂,大爷,你有新的信件了!从此,老陈再也不必频繁上下楼检查信箱了,牙也不疼了,你瞅准了,蓝天……不是,微软~~~~~~~~
WSAEventSelect模型
后来,微软的信箱非常畅销,购买微软信箱的人以百万计数……以至于盖茨每天24小时给客户打电话,累得腰酸背痛,喝蚁力神都不好使~~~~~~
微软改进了他们的信箱:在客户的家中添加一个附加装置,这个装置会监视客户的信箱,每当新的信件来临,此装置会发出“新信件到达”声,提醒老陈去收信。盖茨终于可以睡觉了。
Overlapped I/O 事件通知模型
后来,微软通过调查发现,老陈不喜欢上下楼收发信件,因为上下楼其实很浪费时间。于是微软再次改进他们的信箱。新式的信箱采用了更为先进的技术,只要用户告诉微软自己的家在几楼几号,新式信箱会把信件直接传送到用户的家中,然后告诉用户,你的信件已经放到你的家中了!老陈很高兴,因为他不必再亲自收发信件了!
Overlapped I/O 完成例程模型
老陈接收到新的信件后,一般的程序是:打开信封—-掏出信纸—-阅读信件—-回复信件……为了进一步减轻用户负担,微软又开发了一种新的技术:用户只要告诉微软对信件的操作步骤,微软信箱将按照这些步骤去处理信件,不再需要用户亲自拆信/阅读/回复了!老陈终于过上了小资生活!
IOCP模型
微软信箱似乎很完美,老陈也很满意。但是在一些大公司情况却完全不同!这些大公司有数以万计的信箱,每秒钟都有数以百计的信件需要处理,以至于微软信箱经常因超负荷运转而崩溃!需要重新启动!微软不得不使出杀手锏……
微软给每个大公司派了一名名叫“Completion Port”的超级机器人,让这个机器人去处理那些信件!
其实,上面每种模型都有优点,要根据程序需求而适当选择合适的模型,前面三种模型效率已经比较高,实现起来难道不大,很多一般的网络程序都采用前三种模型,只有对网络要求特别高的一些服务器才会考虑用后面的那些模型。MFC中的CAsyncSocket类就是用的WSAAsyncSelect模型,电驴中也是用的这种,不过在寻找对应socket的时候进行了优化,查找更快,在GridCast中采用的是WSAEventSelect模型,等待。
Java的I/O模型
OIO
OIO 就是同步I/O,
NIO
在JDK 1.4版本之后才开始支持异步IO,其实NIO也是使用操作系统的IO模型,但在各操作系统上的实现方式也不太一样
在Windows系统使用的是Select模型,而不是性能更高的IOCP,原因就是并非所有Windows都支持IOCP,IOCP在windows NT 3.5中被引入,只支持WindowsNT和windows 2000。(参考:http://www.cnblogs.com/jobs/archive/2006/11/22/568023.html)
在Linux系统上使用的是多路复用IO,JDK 6之前用的是poll模型,JDK 7中使用epoll。(参考:http://www.cnblogs.com/jobs/archive/2006/11/22/568022.html)
AIO
JDK 7中出现了AIO,其实AIO就是NIO的增强版,因为JDK 6之前用的是poll,JDK 7用的是epoll,而epoll就是poll的增强版。
参考资料:
http://blog.csdn.net/hguisu/article/details/7453390
Java NIO和操作系统I/O模型
http://wugc.iteye.com/blog/986997
IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇)
http://blog.csdn.net/historyasamirror/article/details/5778378
Java NIO原理 图文分析及代码实现
http://weixiaolu.iteye.com/blog/1479656
Java IO模型
http://blog.csdn.net/shanpengfei77/article/details/8161077
Windows I/O模型、同步/异步、阻塞/非阻塞
http://www.linuxnote.org/windows-i-o-model-synchronous-asynchronous-blocking-non-blocking.html