I/O模型与多路复用

I/O模型与多路复用

本文转载自这里,并加上了自身理解,感觉更透彻了

同步、异步、阻塞、非阻塞

同步 & 异步

同步与异步是针对多个事件(线程/进程)来说的。

  • 如果事件A需要等待事件B的完成才能完成,这种串行执行机制可以说是同步的,这是一种可靠的任务序列,要么都成功,要么都失败。
  • 如果事件B的执行不需要依赖事件A的完成结果,这种并行的执行机制可以说是异步的。事件B不确定事件A是否真正完成,所以是不可靠的任务序列。

同步异步可以理解为多个事件的执行方式和执行时机如何,是串行等待还是并行执行。同步中依赖事件等待被依赖事件的完成,然后触发自身开始执行,异步
中依赖事件不需要等待被依赖事件,可以和被依赖事件并行执行,被依赖事件执行完成后,可以通过回调、通知等方式告知依赖事件。

阻塞 & 非阻塞

阻塞与非阻塞是针对单一事件(线程/进程)来说的。

  • 对于阻塞,如果一个事件在发起一个调用之后,在调用结果返回之前,该事件会被一直挂起,处于等待状态。
  • 对于非阻塞,如果一个事件在发起调用以后,无论该调用当前是否得到结果,都会立刻返回,不会阻塞当前事件。

阻塞与非阻塞可以理解为单个事件在发起其他调用以后,自身的状态如何,是苦苦等待还是继续干自己的事情。非阻塞虽然能提高CPU利用率,但是也带来了系统线程切换的成本,需要在CPU执行时间和系统切换成本之间好好估量一下。

同步阻塞

应用程序执行系统调用,应用程序会一直阻塞,直到系统调用完成。应用程序处于不再消费CPU而只是简单等待响应的状态。当响应返回时,数据被移动到用户空间的缓冲区,应用程序解除阻塞。

此处输入图片的描述

同步非阻塞

设备以非阻塞形式打开,I/O操作不会立即完成,read操作可能会返回一个错误代码。应用程序可以执行其他操作,但需要请求多次I/O操作,直到数据可用。

此处输入图片的描述

同步非阻塞形式实际上是效率低下的,因为:

  • 应用程序需要在不同的任务之间切换。异步非阻塞是你只需要执行当前任务,系统调用会主动通知你,不用频繁切换。
  • 数据在内核中变为可用到调用read返回数据之间存在时间间隔,会造成整体数据吞吐量降低

异步非阻塞

应用程序的其他处理任务与I/O任务重叠进行。读请求会立即返回,说明请求已经成功发起(成不成功另说),应用程序不被阻塞,继续执行其它处理操作。当read响应到达,将数据拷贝到用户空间,产生信号或者执行一个基于线程回调函数完成I/O处理。应用程序不用在多个任务之间切换。

此处输入图片的描述

非阻塞I/O和异步I/O区别在于,在非阻塞I/O中,虽然进程大部分时间不会被block,但是需要不停的去主动check,并且当数据准备完成以后,也需要应用程序主动调用recvfrom将数据拷贝到用户空间;异步I/O则不同,就像是应用程序将整个I/O操作交给了内核完成,然后由内核发信号通知。期间应用程序不需要主动去检查I/O操作状态,也不需要主动从内核空间拷贝数据到用户空间。
相当于应用程序将IO完全托管给了内核,自己则去做其他的事了。

非阻塞I/O看起来是non-blocking的,但是只是在内核数据没准备好时,当数据准备完成,recvfrom需要从内核空间拷贝到用户空间,这个时候其实是被block住的。
而异步I/O是当进程发起I/O操作后,再不用主动去请求,直到内核数据准备好并发出信号通知,整个过程完全没有block。

没有异步阻塞,都异步了都不管了,还阻塞个P啊

几种常用I/O模型

BIO(同步阻塞)

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

服务器需要监听端口号,客户端通过IP和端口与服务器简历TCP连接,以同步阻塞的方式传输数据。服务端设计一般都是 客户端-线程模型,新来一个客户端连接请求,就新建一个线程处理连接和数据传输

当客户端连接较多时就会大大消耗服务器的资源,线程数量可能超过最大承受量

伪异步I/O (带线程池的同步阻塞)

与BIO类似,只是将客户端-线程的模式换成了线程池,可以灵活设置线程池的大小。但这只是对BIO的一种优化手段,并没有解决线程连接的阻塞问题。

NIO (异步非阻塞)

总结:一个请求一个线程,连接注册在多路复用器上,再启动线程,不停询问IO操作

同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。用户进程也需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问。

利用selector多路复用器轮询为每一个用户创建连接,这样就不用阻塞用户线程,也不用每个线程忙等待。只使用一个线程轮询I/O事件,比较适合高并发,高负载的网络应用,充分利用系统资源快速处理请求返回响应消息,

适合:连接又多 IO时间又短

AIO (异步非阻塞,NIO升级版)

总结:一个有效请求一个线程。

异步非阻塞,需要操作系统内核线程支持,一个用户线程发起一个请求后就可以继续执行,内核线程执行完系统调用后会根据回调函数完成处理工作。

适合: I/O任务较长(不想等待浪费时间)

I/O多路复用

速记:挨个访问,准备好了的再建立连接。

多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行(比如使用线程池)。

此处输入图片的描述
这样在处理1000个连接时,只需要1个线程监控就绪状态,对就绪的每个连接开一个线程处理就可以了,这样需要的线程数大大减少,减少了内存开销和上下文切换的CPU开销。

本质:(NIO)同步非阻塞I/O

优势:能处理更多的连接。系统开销小,不需要创建和维护额外线程或进程。

适合:处理多个客户端接入请求时

过程:
通过把多个I/O的阻塞复用到同一个select阻塞上,一个进程监视多个描述符(Socket),一旦某个描述符就位, 能够通知程序进行读写操作。因为多路复用本质上是同步I/O,都需要应用程序在读写事件就绪后自己负责读写。

应用场景
服务器需要同时处理多个处于监听状态或者多个连接状态的套接字
需要同时处理多种网络协议的套接字
一个服务器处理多个服务或协议
目前支持多路复用的系统调用有select, poll, epoll。

未完持续

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值