UNIX提供的5种IO模型:
-
阻塞模型
-
阻塞IO模型:
-
IO复用模型:
-
信号驱动IO模型:
对于五种IO模型我这里用自己的白话再复述一遍,加深理解,如果要看权威的解释可以自己去看《Netty权威指南》。
阻塞IO
- 进程:那老头,有数据要我处理没有。
- 内核:大爷,现在没有数据,我现在就去准备,您老先等等。
- 内核把数据准备好,并从内核复制到用户控件。
- 内核:大爷,有数据了,给您,您慢走。
非阻塞IO
- 进程:那哥们儿,有数据要处理不?
- 内核:暂时没有数据。
- 进程:好勒,我先干别的去了。
- 进行通过轮询的方式不断问内核有没有要处理的数据,直到。
- 进程:哥们儿,有数据要处理不?
- 内核:挨千刀的,一直问一直问,数据在这里,拿起爬。
- 进程:好勒,我先拿走处理了,等下我还要来问哦。
IO复用
- 进程:那哥们儿,我要A/B/C这些数据,有没得?
- 内核:都没有,你先等着。
- 内核去准备数据,直到其中某个数据准备好。
- 内核:小子,数据A准备好了,可以取了。
- 进程:哦,数据A有了哈,那谁,可以拿走了,我继续等等剩下的数据。
信号驱动IO
- 进程:兄弟,我要数据A,这是我电话,有数据了给我打电话。
- 内核准备数据,直到数据准备好。
- 内核:有数据了,需要的时候来取嘛。
- 进程:嘿,兄弟,又见面了,数据给我吧。
- 内核:给你了,拿走吧。
异步IO
- 进程:兄弟,我要数据A,有了麻烦给我邮寄过来,我先回去了。
- 内核准备数据,直到数据准备好,并复制到用户缓冲区。
- 内核:给进程打电话说数据已经给你邮寄过去了,你签收一下。
epoll
目前支持IO多路复用的系统调用有select、pselect、poll、epoll。epoll相对select做了以下改进:
-
支持一个进程打开的socket描述符(FD)不受限制(仅受限于操作系统的最大文件句柄数)。
select单个进程所能打开的FD受限制与FD_SIZE,默认值是1024
1GB内存的机器上大约是10万个句柄,可以通过cat/proc/sys/fs/file-max查看 -
IO效率不会随着FD数目的增加而线性下降。
select/poll每次调用都会线性的扫描全部的socket集合,导致效率呈线性下降。
epoll是根据每个fd上面的callback函数实现的。那么只有“活跃”的socket才会去主动调用callback函数,其他idle状态则不会。 -
使用mmap加速内核与用户空间的消息传递
mmap:一种内存映射文件的方法。
epoll使用你mmap让内核与用户空间共享同一块内存
- epoll的API更简单
IO发展史
- JDK1.0到JDK1.3,IO库非常原始。
- JDK1.4 NIO以JSR-51的身份正式随JDK发布。新增了java.nio包,提供了进行异步IO的开发API和类库。
- JDK1.7 进行了NIO升级,被称为NIO2.0.