NIO 看破也说破(三)—— 不同的 IO 模型

用户头像
小眼睛聊技术
关注
发布于: 2020 年 05 月 11 日
NIO 看破也说破(三)—— 不同的IO模型

上两节我们提到了select 和 poll函数,查看man手册:



SELECT(2) Linux Programmer's Manual SELECT(2)
NAME
select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchronous I/O multiplexing



POLL(2) Linux Programmer's Manual POLL(2)
NAME
poll, ppoll - wait for some event on a file descriptor
SYNOPSIS
#include <poll.h>

synchronous I/O multiplexing中文解释是同步的多路复用,因此select 是一个同步的I/O多路复用模式。Unix共五种I/O模型:

  • 阻塞I/O

  • 非阻塞I/O

  • I/O多路复用

  • 信号驱动

  • 异步I/O



信号驱动和真正的异步I/O并不常用,我们重点说一下前三个。



阻塞和非阻塞的概念描述的是用户线程调用内核IO操作的方式:阻塞是指IO操作需要彻底完成后才返回到用户空间;而非阻塞是指IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成

阻塞I/O



ServerSocket server = new ServerSocket(8080);
while (true) {
Socket socket = server.accept();
System.out.println("链接端口:" + socket.getPort());
InputStream inputStream = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String str = null;
while ((str = reader.readLine()) != null) {
System.out.println("接受:" + str);
socket.getOutputStream().write("ok\n".getBytes());
socket.getOutputStream().flush();
if ("over".equals(str)) {
System.out.println("要关闭了");
socket.close();
break;
}
}
System.out.println("===========");
}

当有数据获取时,用户线程要释放cpu,直到数据由内核处理完成,整个过程用户线程是阻塞的。

阻塞IO



用户线程调用内核IO操作,需要等IO彻底完成后才返回到用户空间,因此是阻塞IO

非阻塞I/O



ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8888));
serverSocketChannel.configureBlocking(false);
while (true) {
SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel == null) {
System.out.println("没有链接 ");
continue;
}
System.out.printf("新链接,端口是 %s", ((InetSocketAddress) socketChannel.
getRemoteAddress()).getPort());
ByteBuffer ds = ByteBuffer.allocate(10);
socketChannel.read(ds);
System.out.println("接受数据");
}



非阻塞IO

IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成,因此是非阻塞的。(用户线程不因为I/O还未到达,一直傻傻的等待,而是需要不断去问内核是否有可用的数据。在准备就绪的情况下获取数据。



补充一个gif(刷新查看):



I/O多路复用



非阻塞IO中需要用户线程在每个IO通路上,各自不断轮询IO状态,来判断是否有可处理的数据。如果把一个连接的可读可写事件剥离出来,使用单独的线程来对其进行管理。多个IO通路,都复用这个管理器来管理socket状态,这个叫I/O多路复用。



多路复用



多路复用在内核中提供了select,poll,epoll三种方式:

select

原理示意



select

特点

只能处理有限(不同系统参数:1024/2048)个socket

select监控socket时不能准确告诉用户是哪个socket有可用数据,需要轮询判断



poll

原理示意

poll

特点

与select没区别

采用链表实现,取消了文件个数的限制

epoll

原理示意

epoll



epoll_wait 直接检查链表是不是空就知道是否有文件描述符准备好了

fd 上的事件发生时,与它对应的回调函数就会被调用把fd 加入链表,其他处于“空闲的”状态的则不会被加入

epoll从上面链表中获取有事件发生的fd



epoll准确的表述应该是I/O事件通知器:

EPOLL(7) Linux Programmer's Manual EPOLL(7)
NAME
epoll - I/O event notification facility
SYNOPSIS
#include <sys/epoll.h>

特点

没有最大连接限制

可以直接告诉用户程序哪一个,哪个连接有数据了



epoll详细的介绍可以参考我的专辑 http://mp.weixin.qq.com/mp/homepage?__biz=MzI3MDYwOTYwOA==&hid=2&sn=b7d5d6aa0b9f18c382a97f146c02b540&scene=18#wechat_redirect 中的第二篇文章《读懂才会用:Redis源码系列》

同步异步的概念



同步和异步的概念描述的是用户线程与内核的交互方式:

同步是指用户线程发起IO请求后需要等待或者轮询内核IO操作完成后才能继续执行;异步是指用户线程发起IO请求 后仍继续执行,当内核IO操作完成后会通知用户线程,或者调用用户线程注册的回调函数。



因此 阻塞I/O,非阻塞I/O,I/O多路复用,都属于同步调用。只有实现了特殊API的AIO才是异步调用,之后单开一篇讲解。

AIO(7) Linux Programmer's Manual AIO(7)
NAME
aio - POSIX asynchronous I/O overview
DESCRIPTION
The POSIX asynchronous I/O (AIO) interface allows applications to initiate one or more I/O operations that are performed asyn‐
chronously (i.e., in the background). The application can elect to be notified of completion of the I/O operation in a variety of
ways: by delivery of a signal, by instantiation of a thread, or no notification at all.



系列

NIO 看破也说破(一)—— Linux/IO 基础

NIO 看破也说破(二)—— Java 中的两种 BIO

NIO 看破也说破(三)—— 不同的 IO 模型

NIO 看破也说破(四)—— Java 的 NIO

NIO 看破也说破(五): 搞,今天就搞,搞懂Buffer



关注我



如果您在微信阅读,请您点击链接 关注我 ,如果您在 PC 上阅读请扫码关注我,欢迎与我交流随时指出错误



发布于: 2020 年 05 月 11 日 阅读数: 1975
用户头像

小眼睛聊技术

关注

欢迎关注公众号“小眼睛聊技术” 2018.11.12 加入

互联网老兵,关注产品、技术、管理

评论 (9 条评论)

发布
用户头像
喜欢你的文风。图的质量很高,也不啰嗦
2020 年 05 月 16 日 21:29
回复
谢谢,欢迎关注。也欢迎关注我的公众号。
2020 年 05 月 16 日 22:38
回复
用户头像
看不懂了,非阻塞 IO 的图有点不懂,作者能着重细节讲下吗
2020 年 05 月 14 日 20:32
回复
我补充了一个gif,你刷新看看,是否能看懂
2020 年 05 月 15 日 01:57
回复
看懂了。但是有个问题,其实非阻塞IO和IO多路复用在全局也是阻塞的,因为他们有两个步骤:
1. 是否有数据
2. 读数据
在这两种 IO 模型中,第一步是非阻塞的,但是第二部读数据是阻塞的
2020 年 06 月 17 日 16:40
回复
用户头像
最近高产啊,首页继续推荐啦。
2020 年 05 月 11 日 13:43
回复
梳理下自己🤦‍♂️
2020 年 05 月 11 日 20:52
回复
这个系列继续更新了,您看是否符合推荐的标准 Thanks♪(・ω・)ノ
2020 年 05 月 19 日 15:38
回复
没有更多了
NIO 看破也说破(三)—— 不同的IO模型