四种主要的IO模型


前言

常见的IO模型有四种:同步阻塞IO、同步非阻塞IO、IO多路复用、异步IO。其中,

  1. 阻塞与非阻塞的区别
      阻塞与非阻塞都指的是用户空间程序的执行状态。阻塞IO指的是需要内核IO操作彻底完成后,才返回到用户空间执行用户的操作。
      阻塞是指用户空间(调用线程)一直在等待,而不能干别的事情;非阻塞是指用户空间(调用线程)拿到内核返回的状态值就返回自己的空间,就可以去完成别的任务。
  2. 同步与异步的区别
      同步IO是一种用户空间与内核空间的IO发起方式。同步IO是指用户空间的线程是主动发起IO请求的一方,内核空间是被动接收方;异步IO是指系统内核是主动发起IO请求的一方,用户空间的线程是被动接受方。

1、同步阻塞IO(Blocking IO)

  在Java中,默认创建的socket都是阻塞的。由用户空间向内核空间发起IO请求,等到内核IO操作彻底完成后,才返回到用户空间执行用户操作。
  在阻塞式IO模型中,Java程序从IO系统调用开始,直到系统调用返回,在这段时间内,Java进程是阻塞的。返回成功后,应用进程开始处理用户空间的缓存区数据。

## 流程(以一次socket的read读操作系统调用为例): 1. 从Java启动IO读的read系统调用开始,用户线程就进入阻塞状态。 2. 当系统内核收到read系统调用,就开始准备数据。一开始,数据可能还没有到达内核缓冲区(例如还未收到一个完整的socket数据包),这个时候内核就要开始等待。 3. 内核一直等到完整的数据到达,就会将数据从内核缓冲区复制到用户缓冲区(用户空间的内存),然后内核返回结果(例如返回复制到用户缓冲区中的字节数)。 4. 直到内核返回后,用户线程才会解除阻塞的状态,重新运行。
优点缺点
1. 应用程序开发简单;2.在阻塞等待数据期间,用户线程挂起,基本不会占用CPU资源。一般情况下,会为每个连接配备一个独立的线程,每个线程维护一个连接的IO操作

当在高并发的应用场景下,需要大量的线程来维护大量的网络连接,内存、线程切换开销巨大。阻塞IO不适合在高并发应用场景下。

2、同步非阻塞IO(Non-blocking IO)

  同步非阻塞IO简称为NIO模式。由用户空间主动发起IO请求,但是用户空间的程序不需要等待内核IO操作彻底完成,可以立即返回用户空间执行用户的操作,即处于非阻塞状态,与此同时,内核会立即返回给用户一个状态值。
  在NIO模型中,应用程序一旦开始IO系统调用,会出现以下两种情况:

  1. 在内核缓冲区中没有数据的情况下,系统调用会立即返回,返回一个调用失败的信息。
  2. 在内核缓冲区中有数据的情况下,是阻塞的,直到数据从内核缓冲复制到用户进程缓冲。复制完成后,系统调用返回成功,应用进程开始处理用户空间的缓存数据。
## 流程(以一次socket的read读操作系统调用为例):
  1. 在内核数据没有准备好的阶段,用户线程发起IO请求时,立即返回。所以为了读取到最终的数据,用户线程需要不断地发起IO系统调用。
  2. 内核数据到达时,用户线程发起系统调用,用户线程阻塞。内核开始复制数据,它会将数据从内核缓冲区复制到用户缓冲区(用户空间的内存),然后内核返回结果(例如返回复制到用户缓冲区中的字节数)。
  3. 用户线程读到数据后,才会解除阻塞状态,重新运行起来。

同步非阻塞IO的特点:应用程序的线程需要不断地进行IO系统调用,轮询数据是否已经准备好。如果没有准备好,就继续轮询,直到完成IO系统调用为止。即一次IO请求可能无法获取数据。

优点缺点
每次发起的IO系统调用,在内核等待数据过程中可以立即返回。用户线程不会阻塞,实时性较好。不断地轮询内核,会占用大量的CPU时间,效率低下。

3、IO多路复用模型(IO Multiplexing)

  为了避免同步非阻塞IO模型中轮询等待的问题,有了IO多路复用模型。在IO多路复用模型中,用到了一种新的系统调用,用于查询IO的就绪状态。在Linux系统中,对应的系统调用为select/poll、epoll系统调用。通过该系统调用,一个进程可以监视多个文件描述符,一旦某个描述符就绪(内核缓冲区可读/可写),内核能够将就绪的状态返回给应用程序。随后,应用程序根据就绪的状态,进行相应的IO系统调用(读写过程为阻塞状态)。

几种系统调用的区别:

1.select

时间复杂度为O(n)。select 的核心功能是调用tcp文件系统的poll函数,不停的查询,若是没有想要的数据,主动执行一次调度(防止一直占用cpu),直到有一个链接有想要的消息为止。select的执行方式基本就是不停的调用poll,直到有需要的消息为止。

优点

①. select的可移植性更好,在某些Unix系统上不支持poll()。
②. select对于超时值提供了更好的精度:微秒,而poll是毫秒。

缺点

①. 每次调用select,都须要把fd(文件描述符)集合从用户态拷贝到内核态,这个开销在fd不少时会很大;
②. 同时每次调用select都须要在内核遍历传递进来的全部fd,这个开销在fd不少时也很大;
③. select支持的文件描述符数量过小了,默认是1024。

2.poll

poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,而后查询每一个fd对应的设备状态,若是设备就绪则在设备等待队列中加入一项并继续遍历,若是遍历完全部fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。这个过程经历了屡次无谓的遍历。poll还有一个特色是“水平触发”,若是报告了fd后,没有被处理,那么下次poll时会再次报告该fd。

优点

①. poll() 不要求开发者计算最大文件描述符加一的大小。

②. poll() 在应付大数目的文件描述符的时候速度更快,相比于select。

③. 它没有最大链接数的限制,缘由是它是基于链表来存储的。

缺点

①. 大量的fd的数组被总体复制于用户态和内核地址空间之间,而无论这样的复制是否是有意义;
②. 与select同样,poll返回后,须要轮询pollfd来获取就绪的描述符。

3.epoll

epoll是在Linux2.6内核中提出的,是之前的select和poll的增强版本。相对于select和poll来说,epoll更加灵活,没有描述符限制。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。

三者区别

select,poll实现须要本身不断轮询全部fd集合,直到设备就绪,期间可能要睡眠和唤醒屡次交替。而epoll其实也须要调用epoll_wait不断轮询就绪链表,期间也可能屡次睡眠和唤醒交替,可是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,可是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空即可,这节省了大量的CPU时间。这就是回调机制带来的性能提高。

4、异步IO模型(Asynchronous IO)

  异步IO模型(Asynchronous IO,简称为AIO)。AIO的基本流程是:用户线程通过系统调用,向内核注册某个IO操作。内核在整个IO操作(包括数据准备、数据复制)完成后,通知用户程序,用户执行后序的业务操作。在异步IO模型中,用户程序都不会发生阻塞。

流程(以一次socket的read读操作系统调用为例):

  1. 当用户线程发起了read系统调用,立即就可以去做其他的事,用户线程不阻塞。
  2. 内核开始IO的第一个阶段:准备数据。等到数据准备好,内核就会将数据从内核缓冲区复制到用户缓冲区(用户空间的内存)。
  3. 内核会给用户线程发送一个信号(Singal),或者回调用户线程注册的回调接口,告诉用户线程read操作完成。
  4. 用户线程读取用户缓冲区的数据,完成后续的业务操作。

异步IO模型的特点:在内核等待数据和复制数据的两个阶段,用户线程都不是阻塞的。用户线程需要接受内核的IO操作完成的事件,或者用户线程需要注册一个IO操作完成的回调函数。异步IO也被称为信号驱动IO。

优点缺点
异步IO是真正的异步输入输出,它的吞吐量高于IO多路复用应用程序仅需要进行事件的注册和接收,其余的工作都留给了操作系统,需要底层内核的支持。

  目前只有Windows系统下通过IOCP实现了真正的异步IO,在Linux系统下,异步IO底层实现仍使用epoll,与IO多路复用相同,在性能上没有明显的优势。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux IO 模型是指 Linux 操作系统中的 IO 处理机制。它的目的是解决多个程序同时使用 IO 设备时的资源竞争问题,以及提供一种高效的 IO 处理方式。 Linux IO 模型主要分为三种:阻塞 IO、非阻塞 IOIO 多路复用。 阻塞 IO 指的是当程序进行 IO 操作时,会被挂起直到 IO 操作完成,这种方式简单易用,但是对于高并发环境不太适用。 非阻塞 IO 指的是程序进行 IO 操作时,如果无法立即完成,会立即返回一个错误码,程序可以通过循环不断地进行 IO 操作来实现轮询的效果。非阻塞 IO 可以提高程序的响应速度,但是会增加程序的复杂度。 IO 多路复用指的是程序可以同时监听多个 IO 设备,一旦有 IO 事件发生,就会立即执行相应的操作。IO 多路复用可以提高程序的效率,但是需要程序员手动编写代码来实现。 Linux IO 模型还有其他的实现方式,比如信号驱动 IO异步 IO 等。但是这些方式的使用比较复杂,一般不常用。 ### 回答2: Linux中的IO模型是指操作系统在处理输入输出的过程中所遵循的一种方式。它主要包括阻塞IO、非阻塞IO、多路复用IO异步IO四种模型。 阻塞IO是最简单的IO模型,当一个IO操作发生时,应用程序会被阻塞,直到IO操作完成才能继续执行。这种模型的特点是简单直接,但是当有多个IO操作时会造成线程的阻塞,影响系统的性能。 非阻塞IO是在阻塞IO的基础上发展而来的,应用程序在发起一个IO操作后可以继续执行其他任务,不必等待IO操作的完成。但是需要通过轮询来不断地检查IO操作是否完成,效率相对较低。 多路复用IO使用select、poll、epoll等系统调用来监听多个IO事件,当某个IO事件就绪时,应用程序才会进行读写操作,避免了前两种模型的效率问题。多路复用IO模型适用于连接数较多时的场景,如服务器的网络通信。 异步IO是最高效的IO模型,应用程序发起一个IO操作后,立即可以执行其他任务,不需要等待IO操作的完成。当IO操作完成后,操作系统会通知应用程序进行后续处理。异步IO模型常用于高吞吐量、低延迟的应用,如高性能服务器和数据库等。 总之,Linux IO模型提供了多种不同的方式来处理输入输出,每种模型都有其适用的场景和特点。选择合适的IO模型可以提高系统的性能和效率。 ### 回答3: Linux IO模型是指操作系统中用于处理输入输出操作的一种方法或机制。在Linux中,常见的IO模型有阻塞IO、非阻塞IOIO多路复用和异步IO。 阻塞IO是最基本的IO模型,当应用程序发起一个IO请求时,它将一直阻塞等待直到IO操作完成,期间无法做其他任务。虽然简单易用,但是对资源的利用不高。 非阻塞IO在发起一个IO请求后,不会阻塞等待IO操作完成,而是立即返回并继续做其他任务。应用程序需要不断地轮询IO操作状态,直到操作完成。由于需要不断轮询,对CPU的占用较高,但可以提高资源的利用率。 IO多路复用是通过一个线程同时监听多个IO事件,从而实现并发处理多个IO操作。在IO多路复用模型中,应用程序不需要进行轮询,而是通过调用select、poll或epoll等系统调用监听多个文件描述符的IO事件。这样可以在单个线程中处理多个IO操作,提高并发性能。 异步IO模型在发起一个IO请求后,应用程序不需要等待IO操作完成,而是继续做其他任务。当IO操作完成后,操作系统会通知应用程序。异步IO模型需要操作系统的支持,效率较高,但实现较为复杂。 通过选择合适的IO模型,可以根据不同的应用场景来提高IO操作的效率和性能。例如,对于需要同时处理大量连接的服务器应用,IO多路复用是一种常见的选择;而对于需要处理大量IO操作的高性能服务器,则可以考虑使用异步IO模型

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值