四种主要的IO模型

在说IO前,我们来看一下操作系统进行读写的流程

例如:

Java客户端通过write系统调用将数据从用户缓冲区复制到内核缓存区,内核通过客户机网卡将数据发送出去;

服务器通过网卡接收数据至内核缓冲区,Java用户程序通过read系统调用将内核缓冲区中的数据读取至Java进程缓冲区

这是一个典型的系统调用流程

对于服务器IO编程来讲,常见的IO模型有4种

1. 同步阻塞IO

Blocking IO是指用户空间主动发起,需要等内核IO完成后才返回用户空间的IO操作,IO过程中用户进程处于阻塞状态

优点:应用程序开发简单

缺点:需要为每个连接配备一个独立的线程,一个线程维护一个连接IO操作;在高并发的情况下,需要大量的线程来维护连接,内存和线程切换的开销也会增大,性能低下


2. 同步非阻塞IO

Non-Blocking IO指用户进程主动发起,不需要等内核IO完成就能立即返回用户空间的IO操作,IO过程中用户进程处于非阻塞状态

注意这里的NIO不是Java的NIO,Java NIO表示New IO

同步非阻塞在调用过程中,如果内核数据没数据的情况下回返回失败,有数据的情况下系统调用阻塞,直至数据复制完成;所以在内核数据没有准备好的情况下,用户线程需要不断的发起IO系统调用,如果准备好了,用户线程阻塞,复制数据至完成(简而言之,用户需要尝试N(N>=1)次后才能读到完整的数据) 

优点:内核在等待数据的过程中,系统IO调用能立即返回,用户线程不会阻塞

缺陷:需要不断轮询内核,占用CPU时间,所以高并发场景下,又是一个凉凉的方案,但是非阻塞这一点还是有价值的,可以基于这一点为基础做一些文章。


3. IO多路复用

IO Multiplexing属于经典的Reactor模式实现,有时也称为异步阻塞IO

此模型有硬性的前提条件:即操作系统必须在硬件上支持多路分离的系统调用select、epoll

IO多路复用的流程如下:

1. 选择器注册

2. 就绪状态轮询

3. 用户线程获取就绪列表后,发起read系统调用

4. 复制完成

相比前两种,IO多路复用涉及两种系统调用:

a. IO操作的系统调用

b. select就绪查询系统调用 (这一点和NIO模型类似需要轮询)

JDK中Java NIO使用的就是多路复用模型

优点:一个选择器查询线程可以处理成千上万连接(解决了NIO模型的问题),用户线程无需创建大量的线程

缺点:本质上select/poll调用是阻塞式的,属于同步IO

 


4. 异步IO

Asynchronous IO指用户胡进程变成被动接收者,内核空间称为主动调用者,当用户进程收到通知时,数据已被内核读取完毕并放在用户缓存区内

异步IO流程如下:

1. 用户线程发起read系统调用,立即可以去做其他事情,用户线程不阻塞

2. 内核IO进行数据准备至用户缓冲区

3. 内核给用户线程发送信号或进行回调方法,告知用户线程read系统调用已经完成

4. 用户线程读取用户缓冲区数据,完成后续业务操作

优点:相比上述三种模型可以真正做到用户线程不阻塞

缺点:应用程序仅做了注册和接收,其余工作都给了操作系统,需要底层内核提供支持(其实事情还是那些事情,异步IO相当于把自己要做的事情外包给了操作系统,如果操作系统本身做的好,性能高于自己实现,那么可以说异步IO的性能更好,操作系统从内部去实现,理论上是性能更好的)

异步IO在Linux2.6版本引入,JDK支持一般的原因,导致目前较多的网络应用程序大多采用IO多路复用(例如Netty)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值