IO模型

IO模型

Linux的五种IO模型

五种IO模型包括:阻塞IO、非阻塞IO、IO多路复用、信号驱动IO、异步IO

简单介绍一下几个linux函数

recvfrom
Linux系统提供给用户用于接收网络IO的系统接口。从套接字上接收一个消息,可同时应用于面向连接和无连接的套接字。

成功完成后,这两个调用都将返回消息的长度。 如果消息太长而无法容纳在提供的缓冲区中,则多余的字节可能会被丢弃,此时,返回值则取决于接收消息的套接字类型。

如果套接字上没有可用的消息,则接收调用将阻塞等待消息到达,除非套接字是非阻塞的,在这种情况下,将返回值-1且外部变量errno设置为EAGAIN 或EWOULDBLOCK。

select
select系统调用允许程序同时在多个底层文件描述符上,等待输入的到达或输出的完成。以数组形式存储文件描述符,64位机器默认2048个。当有数据准备好时,无法感知具体是哪个流OK了,所以需要一个一个的遍历,函数的时间复杂度为O(n)

poll
链表形式存储文件描述符,没有长度限制。本质与select相同,函数的时间复杂度也为O(n)

epoll
是基于事件驱动的,如果某个流准备好了,会以事件通知,知道具体是哪个流,因此不需要遍历,函数的时间复杂度为O(1)

sigaction
用于设置对信号的处理方式,也可检验对某信号的预设处理方式。Linux使用SIGIO信号来实现IO异步通知机制。

selectpollepoll
操作方式遍历遍历回调
底层实现数组链表红黑树
IO效率每次调用都进行线性遍历,时间复杂度为O(n)每次调用都进行线性遍历,时间复杂度为O(n)事件通知方式,每当fd就绪,系统注册的回调函数就会被调用,将就绪fd放到readyList里面,时间复杂度O(1)
最大连接数1024(x86)或2048(x64)无上限无上限
fd拷贝每次调用select,都需要把fd集合从用户态拷贝到内核态每次调用poll,都需要把fd集合从用户态拷贝到内核态调用epoll_ctl时拷贝进内核并保存,之后每次epoll_wait不拷贝

同步&异步

同步和异步是针对应用程序和内核交互而言的,也可理解为被**被调用者(操作系统)**的角度来说。
同步是用户进程触发IO操作并等待或轮询的去查看是否就绪,而异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知,需要CPU支持

阻塞&非阻塞

阻塞和非阻塞是针对于进程在访问数据的时候,也可理解为**调用者(程序)**角度来说。根据IO操作的就绪状态来采取的不同的方式。
阻塞方式下读取或写入方法将一直等待,而非阻塞方式下读取或写入方法会立即返回一个状态值。

同步阻塞IO模型(Blocking IO)

场景描述:我和女友点完餐后,不知道什么时候能做好,只好坐在餐厅里面等,直到做好,然后吃完才离开。女友本想还和我一起逛街的,但是不知道饭能什么时候做好,只好和我一起在餐厅等,而不能去逛街,直到吃完饭才能去逛街,中间等待做饭的时间浪费掉了。

同步阻塞 IO 模型是最常用的一个模型,也是最简单的模型。在linux中,默认情况下所有的socket都是blocking

阻塞IO的执行过程是进程进行系统调用等待内核将数据准备好并复制到用户态缓冲区后,进程放弃使用CPU一直阻塞在此,直到数据准备好。

同步非阻塞IO模型(nonblocking IO)

场景描述:我女友不甘心白白在这等,又想去逛商场,又担心饭好了。所以我们逛一会,回来询问服务员饭好了没有,来来回回好多次,饭都还没吃都快累死了啦。这就是非阻塞。需要不断的询问,是否准备好了。

每隔一段时间应用程序就去询问内核是否有数据准备好。如果就绪,就进行拷贝操作;如果未就绪,就不阻塞程序,内核直接返回未就绪的返回值,等待用户程序下一个轮询。

大致经历两个阶段:

  • 等待数据阶段:未阻塞, 用户进程需要盲等,不停的去轮询内核。
  • 数据复制阶段:阻塞,此时进行数据复制。

在这两个阶段中,用户进程只有在数据复制阶段被阻塞了,而等待数据阶段没有阻塞,但是用户进程需要盲等,不停地轮询内核,看数据是否准备好。

同步非阻塞方式相比同步阻塞方式:

优点:能够在等待任务完成的时间里干其他活了(包括提交其他任务,也就是 “后台” 可以有多个任务在同时执行)。

缺点:任务完成的响应延迟增大了,因为每过一段时间才去轮询一次read操作,而任务可能在两次轮询之间的任意时间完成。这会导致整体数据吞吐量的降低。

IO 多路复用(IO multiplexing)

场景描述:与第二个方案差不多,餐厅安装了电子屏幕用来显示点餐的状态,这样我和女友逛街一会,回来就不用去询问服务员了,直接看电子屏幕就可以了。这样每个人的餐是否好了,都直接看电子屏幕就可以了。

相比于阻塞IO模型,多路复用只是多了一个select/poll/epoll函数

对于客户端来说,一般感受不到阻塞,因为请求来了,可以用放到线程池里执行;但对于执行select的操作系统而言,是阻塞的,需要阻塞地等待某个套接字变为可读

信号驱动式IO(signal-driven IO)

首先我们允许Socket进行信号驱动IO,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。

异步IO模型(asynchronous IO)

场景描述:女友不想逛街,又餐厅太吵了,回家好好休息一下。于是我们叫外卖,打个电话点餐,然后我和女友可以在家好好休息一下,饭好了送货员送到家里来。这就是典型的异步,只需要打个电话说一下,然后可以做自己的事情,饭好了就送来了。

相对于同步IO,异步IO不是顺序执行。用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知。IO两个阶段,进程都是非阻塞的。

JAVA的IO模型

BIO–同步阻塞的编程方式

JDK1.4之前常用的编程方式。
实现过程:首先在服务端启动一个ServerSocket来监听网络请求,客户端启动Socket发起网络请求,默认情况下ServerSocket会建立一个线程来处理此请求,如果服务端没有线程可用,客户端则会阻塞等待或遭到拒绝并发效率比较低

服务器实现的模式是一个连接一个线程,若有客户端有连接请求服务端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销。当然,也可以通过线程池机制改善。

使用场景
BIO适用于连接数目比较小且固定的架构,对服务器资源要求高,并发局限于应用中。

NIO–同步非阻塞的编程方式

NIO 本身是基于事件驱动思想来完成的,当 socket 有流可读或可写入时,操作系统会相应地通知应用程序进行处理,应用再将流读取到缓冲区或写入操作系统。一个有效的请求对应一个线程,当连接没有数据时,是没有工作线程来处理的。

服务器实现模式为一个请求一个通道,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有 I/O 请求时启动一个线程进行处

使用场景:NIO 方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程复杂,JDK1.4 开始支持。

NIO中的几种重要角色

有缓冲区Buffer,通道Channel,多路复用器Selector。

Buffer

在NIO库中,所有数据都是用缓冲区(用户空间缓冲区)处理的。在读取数据时,它是直接读到缓冲区中的;在写入数据时,也是写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。
缓冲区实际上是一个数组,并提供了对数据的
结构化访问
以及维护读写位置等信息。

Buffer的应用固定逻辑

写操作顺序

  1. clear()
  2. put() -> 写操作
  3. flip() ->重置游标
  4. SocketChannel.write(buffer); ->将缓存数据发送到网络的另一端
  5. clear()

读操作顺序

  1. clear()
  2. SocketChannel.read(buffer); ->从网络中读取数据
  3. buffer.flip()
  4. buffer.get() ->读取数据
  5. buffer.clear()

Channel

nio中对数据的读取和写入要通过Channel,它就像水管一样,是一个通道。通道不同于流的地方就是通道是双向的,可以用于读、写和同时读写操作。

Selector

多路复用器,用于注册通道。客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理

AIO–异步非阻塞编程方式

进行读写操作时,只须直接调用api的read或write方法即可。一个有效请求对应一个线程,客户端的IO请求都是OS先完成了再通知服务器应用去启动线程进行处理。

使用场景:AIO 方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用 OS 参与并发操作,编程比较复杂,JDK1.7 开始支持。

总结

从效率上来说,可以简单理解为阻塞IO<非阻塞IO<多路复用IO<信号驱动IO<异步IO。从同步和异步来说,只有异步IO模型是异步的,其他均为同步。

参考https://zhuanlan.zhihu.com/p/127170201

  • 40
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值