聊聊I/O

作者: NeXt4 | 来源:发表于2020-06-07 17:05 被阅读0次

1. 五种IO模型

1.1 同步阻塞IO

最简单的一种IO模型,用户线程在进行IO操作的时候通常是个系统调用,用户线程会由用户空间进入内核空间,内核空间数据包准备好后会将数据拷贝到用户空间,这个时候线程在用户态继续执行。

老李去火车站买票,排队三天买到一张退票。
耗费:在车站吃喝拉撒睡 3天,其他事一件没干。

1.2 同步非阻塞IO

同步非阻塞IO即在同步阻塞的基础之上将socket设置为NONBLOCK。这样用户线程在发起IO操作之后可以立即返回,但是用户线程需要不断轮询来请求数据。

老李去火车站买票,隔12小时去火车站问有没有票,三天后买到一张票。
耗费:往返车站6次,路上6小时,其他时间做了好多事。

1.3 多路复用IO

Reactor设计模式,多路复用模型从流程上和同步阻塞的区别不大,主要区别在于操作系统为用户提供了同时轮询多个IO句柄来查看是否有IO事件的接口(如select),这从根本上允许用户可以使用单个线程来管理多个IO句柄。

select/poll版本: 老李去火车站买票,委托黄牛,然后每隔6小时电话黄牛询问,黄牛三天内买到票,然后老李去火车站交钱领票。
耗费:往返车站2次,路上2小时,黄牛手续费100元,打电话17次

epoll版本:老李去火车站买票,委托黄牛,黄牛买到后即通知老李去领,然后老李去火车站交钱领票。
耗费:往返车站2次,路上2小时,黄牛手续费100元,无需打电话

1.4 信号驱动IO

老李去火车站买票,给售票员留下电话,有票后,售票员电话通知老李,然后老李去火车站交钱领票。
耗费:往返车站2次,路上2小时,免黄牛费100元,无需打电话

1.5 异步IO

Proactor设计模式。在异步IO模型中,用户不需要去轮询IO事件,然后才进行数据的读取,处理;在异步IO模型中,IO事件就绪的时候,内核会开启一个独立的内核线程去执行执行IO操作,实现真正的异步IO。这个时候用户线程可以直接读取内核线程准备好的数据。

老李去火车站买票,给售票员留下电话,有票后,售票员电话通知老李并快递送票上门。
耗费:往返车站1次,路上1小时,免黄牛费100元,无需打电话

Java NIO是如何工作的

NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题的有效方式。

那么NIO的本质是什么样的呢?它是怎样与事件模型结合来解放线程、提高系统吞吐的呢?

所有的系统I/O都分为两个阶段:等待就绪和操作。举例来说,读函数,分为等待系统可读和真正的读;同理,写函数分为等待网卡可以写和真正的写。

传统的BIO使用的几个函数都是阻塞的,socket.accept()、socket.read()、socket.write()。

需要说明的是等待就绪的阻塞是不使用CPU的,是在“空等”;而真正的读写操作的阻塞是使用CPU的,真正在"干活",而且这个过程非常快,属于memory copy,带宽通常在1GB/s级别以上,可以理解为基本不耗时。

传统的BIO里面socket.read(),如果TCP RecvBuffer里没有数据,函数会一直阻塞,直到收到数据,返回读到的数据。

对于NIO,如果TCP RecvBuffer有数据,就把数据从网卡读到内存,并且返回给用户;反之则直接返回0,永远不会阻塞。

最新的AIO(Async I/O)里面会更进一步:不但等待就绪是非阻塞的,就连数据从网卡到内存的过程也是异步的。

换句话说,BIO里用户最关心“我要读”,NIO里用户最关心"我可以读了",在AIO模型里用户更需要关注的是“读完了”。

NIO一个重要的特点是:socket主要的读、写、注册和接收函数,在等待就绪阶段都是非阻塞的,真正的I/O操作是同步阻塞的(消耗CPU但性能非常高)。

NIO的事件模型

如何利用事件模型单线程处理所有I/O请求?
NIO有原来的阻塞读写(占用线程)变成了单线程轮询事件,找到可以进行读写的网络描述符。除了事件轮询是阻塞的,剩余的IO都是纯cpu操作,没必要开启线程。

标准/典型的Reactor:
步骤1:等待事件到来(Reactor负责)。
步骤2:将读就绪事件分发给用户定义的处理器(Reactor负责)。
步骤3:读数据(用户处理器负责)。
步骤4:处理数据(用户处理器负责)。

NIO主要事件有读就绪、写就绪、有新连接到来。

用一个死循环选择就绪的事件,会执行系统调用(Linux 2.6之前是select、poll,2.6之后是epoll,Windows是IOCP),还会阻塞的等待新事件的到来。新事件到来的时候,会在selector上注册标记位,标示可读、可写或者有连接到来。

NIO核心组件:事件选择器
它是Java NIO核心组件中的一个,用于检查一个或多个NIO Channel(通道)的状态是否处于可读、可写。实现单线程管理多个Channel,也就是可以管理多个网络连接。

Selector核心在于基于操作系统提供的I/O复用功能,单个线程可以同时监视多个连接描述符,一旦某个连接就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作,常见有select、poll、epoll等不同实现。

NIO的选择器就实现了这样的功能。一个Selector实例可以同时检查一组信道的I/O状态。用专业术语来说,选择器就是一个多路开关选择器,因为一个选择器能够管理多个信道上的I/O操作。然而如果用传统的方式来处理这么多客户端,使用的方法是循环地一个一个地去检查所有的客户端是否有I/O操作,如果当前客户端有I/O操作,则可能把当前客户端扔给一个线程池去处理,如果没有I/O操作则进行下一个轮询,当所有的客户端都轮询过了又接着从头开始轮询;这种方法是非常笨而且也非常浪费资源,因为大部分客户端是没有I/O操作,我们也要去检查;

Java NIO Selector基本工作流程如下:
(1) 初始化Selector对象,服务端ServerSocketChannel对象
(2) 向Selector注册ServerSocketChannel的socket-accept事件
(3) 线程阻塞于selector.select(),当有客户端请求服务端,线程退出阻塞
(4) 基于selector获取所有就绪事件,此时先获取到socket-accept事件,向Selector注册客户端SocketChannel的数据就绪可读事件事件
(5) 线程再次阻塞于selector.select(),当有客户端连接数据就绪,可读
(6) 基于ByteBuffer读取客户端请求数据,然后写入响应数据,关闭channel。

NIO核心组件:缓冲区
Buffer提供了常用于I/O操作的字节缓冲区,常见的缓存区有ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer,分别对应基本数据类型: byte, char, double, float, int, long, short

NIO核心组件:通道
Channel(通道)的概念可以类比I/O流对象,NIO中I/O操作主要基于Channel:
从Channel进行数据读取 :创建一个缓冲区,然后请求Channel读取数据
从Channel进行数据写入 :创建一个缓冲区,填充数据,请求Channel写入数据。

Channel和IO中的Stream(流)是差不多一个等级的。只不过Stream是单向的,譬如:InputStream, OutputStream.而Channel是双向的,既可以用来进行读操作,又可以用来进行写操作。

NIO核心组件:事件处理器
用于处理相应的事件,如读事件、写事件

NIO的问题

使用NIO != 高性能,当连接数<1000,并发程度不高或者局域网环境下NIO并没有显著的性能优势。

NIO并没有完全屏蔽平台差异,它仍然是基于各个操作系统的I/O系统实现的,差异仍然存在。使用NIO做网络编程构建事件驱动模型并不容易,陷阱重重。

推荐大家使用成熟的NIO框架,如Netty,MINA等。解决了很多NIO的陷阱,并屏蔽了操作系统的差异,有较好的性能和编程模型。

总结

  • 所有的系统IO都分为两个操作,等待就绪和操作
  • BIO里用户最关心“我要读”,NIO里用户最关心"我可以读了",在AIO模型里用户更需要关注的是“读完了”
  • NIO的事件模型,主要事件有读就绪、写就绪、有新连接到来。
  • IO是面向流的,NIO是面向缓冲区的。

来源

相关文章

  • 聊聊I/O

    1. 五种IO模型 1.1 同步阻塞IO 最简单的一种IO模型,用户线程在进行IO操作的时候通常是个系统调用,用户...

  • 聊聊JAVA中的I/O

    I/O即为输入输出的意思,在实际应用中的I/O操作主要是针对磁盘或者网络。磁盘的I/O主要是针对文件读写,而网络I...

  • 聊聊flink的Async I/O

    序 本文主要研究一下flink的Async I/O 实例 本实例展示了flink Async I/O的基本用法,首...

  • 聊聊非阻塞I/O编程

    写在前面 随着互联网的发展,面对海量用户高并发业务,传统的阻塞I/O架构已经无能为力,改善阻塞问题是服务器高性能架...

  • 。o゜。゜O。°゜O。°o°o゜o。O

    信仰……゜o。[!+!=I我]。!+!=I我]。!+!=I我]。!+!=I我]。°o°o゜o。[!+!=I我]。!...

  • 2021-04-19

    信仰……゜o。[!+!=I我]。!+!=I我]。!+!=I我]。!+!=I我]。°o°o゜o。[!+!=I我]。!...

  • Linux I/O模型的前世今生

    Linux I/O模型 阻塞式I/O模型 非阻塞式I/O模型 I/O复用式模型 信号驱动式I/O模型 异步I/O模...

  • Socket

    一、I/O 模型阻塞式 I/O非阻塞式 I/OI/O 复用信号驱动 I/O异步 I/O五大 I/O 模型比较 二、...

  • 大厂求职必看!Tomcat线程模型—全网最清晰的讲解!

    UNIX系统的I/O模型 同步阻塞I/O、同步非阻塞I/O、I/O多路复用、信号驱动I/O和异步I/O。 什么是 ...

  • 计算机组成原理(七)输入输出系统

    7.1 I/O系统基本概念 I/O系统由I/O软件和I/O硬件两部分构成。 I/O硬件包括外部设备、I/O接口、I...

网友评论

      本文标题:聊聊I/O

      本文链接:https://www.haomeiwen.com/subject/mtxxtktx.html