IO模型详解及应用

Wesley13
• 阅读 791

如何阅读这篇文章顺序

1.1:了解同步异步和阻塞非阻塞

    1.11: 同步异步

    1.12:阻塞非阻塞

1.2:了解一次read操作需要的步骤

1.3:五种模型

1.1:I/O模型中的同步异步,阻塞非阻塞:

1.11:同步和异步:synchronousasyncronous

    关注的是消息通知机制

同步概念:调用发出之后不会立即返回,但一旦返回,则返回则是最终结果:

异步:调用发出之后,被调用方立即返回消息,但返回的并非最终结果,被调用者通过状态、通知机制等来通知调用者,或通过回调函数来处理结果。

同步异步:关注的是调用者如何等待结果

1.22:阻塞和非阻塞:blocknonblock

阻塞:调用结果返回之前,调用者会被挂起:调用者只有在得到返回结果之后才能继续:

非阻塞:调用者在结果返回之前:不会被挂起,即调用不会阻塞调用者

例子:比如你去饭馆吃面需要等着上面才能吃到。   

阻塞:当你在点面的时候前面排队的人很多,老板和你说一句客官稍等,这时候你没办法做其他事情这就是阻塞。

非阻塞:比如你和老板关系不错,你跟老板说一句给你上面,你就出去买烟估摸时间差不多了就回去了,这就是非阻塞。

  • 异步同步:关注的是调用者等待被调用者返回调用结果时的状态
  • 阻塞和非阻塞:关注的是如何通知被调用者结果已经完成

根据上面的概念划分的话常见的I/O模型分为这五种。

I/O模型:

blocking IO  # 阻塞式IO

nonblocking IO  _# 非阻塞式IO_IO multiplexing # 复用式IO

signal driven #事件驱动IO,事件驱动式IO有通知机制的

通知:

    水平触发:多次通知

    边缘触发:只通知一次

 asynchronous IO # 异步IO

1.2:为了解释I/O模型,举个read操作的例子。

例如:从磁盘一次read操作大体分为两个步骤

用户空间的进程是无法直接访问硬件的,所以步骤大概如下。

当一个用户进程需要进行io操作的时候向系统内核发送调用请求调用什么数据。这时候就分为两个步骤了。

  • 步骤一.当内核得到用户进程通知要调用数据的时候,内核本身是没有这个数据的,数据是在磁盘上的。所以内核会从磁盘加载到自己的内存中(内核内存) # 这个内存不是用户进程的那个内存,虽然内核能这么做,但这是不推荐的。
  • 步骤二.这个时候用户进程还是没有这个数据的,所以用户进程还需要从内核内存中copy一份数据到自己的这个进程内存中。这个就是第二个步骤

真正属于IO操作的步骤是内核内存中的数据到进程内存数据,这个属于真正执行IO操作步骤的阶段。内核内存从磁盘取数据的阶段是等待事件完成阶段。

五种IO模型

阻塞式I/O模型

当调用者发起调用请求之后,此处调用者一方会被挂起,这个时候进程会转入不可中断式睡眠状态,这个时候调用者在得到结果之前什么事情也不能够去做,将一直处于等待过程当中。 阻塞型I/O举例:当一个用户访问你web服务器的时候,这个时候你服务器会有一个进程去处理用户的请求去取数据,这个时候这个进程是被挂起的状态。这个时候这个进程是不能处理其他用户的请求,因为处于睡眠状态。当然事实情况是不会用阻塞式I/O的因为是需要处理两路请求的,一部分网络I/O请求,一部分磁盘I/O请求。一个进程通常情况下只能处理单路I/O的

非阻塞式I/O模型

当调用者发起调用请求时候,被调用者告诉你我收到你的请求了你等着吧~这个时候会有个问题是你必须每过一段时间去问被调用者:好了没?这个叫做盲等待。那到底阻塞好还是非阻塞好。如果一件事情你没办法知道什么时候好。你一遍遍问好了没?还不如直接告诉进程你进入不可中断式睡眠状态吧。盲等待效率不一定高,非阻塞式不一定就是性能好。对于进程而言,由于他没被阻塞,所以他不得不轮询一遍遍的问。当老板告诉你面OK的时候,这个时候数据是从磁盘到了内核内存中了,还没到进程内存中。这个时候调用者去取数据的时候这个时间段还是阻塞的,因为你在取数据不能做其他事情。

这个时候对web服务器来说非阻塞式并没有带来性能的提升。

复用式I/O模型

一般情况下一个进程只能处理一路I/O,一旦这个进程在做I/O操作的时候,其他请求在做什么的时候这个进程都不知道,但我们都知道一个web服务器是需要处理两路I/O的,一路是用户通过网络请求过来,一路是处理磁盘加载到内存中的操作。一旦进程被阻塞在磁盘上,这个时候网络I/O发生异动了(比如用户不请求了)。这个时候阻塞型I/O进程是不得知的。我们没有办法去结束这个进程的,因为他处于不可中断的睡眠状态,你ctrl+C也没用除非他加载完数据。 复用式IO就是在这种情况下被发明在内核中。这个模式是这样的当你发起一个I/O请求的时候,你的操作会交给内核中的一个代理人。这个代理人会将其翻译为内核能理解的请求。这个时候用户请求被阻塞在代理人上而不是内存中。 举例:当你去银行办业务的时候,你们所有人就在柜台人员那里排队,一个个完成。这个时候当你说你要办银行卡的时候就算出卡需要时间,银行人员是不是不能跟你说在旁边等着? 当然咱们还能有这种模式,当你去办业务的时候有个机器让你选择你要办什么业务并给你发一个号码,当你要办卡然后存钱两个业务的时候,这个时候你想办理什么业务的时候都是跟这个代理请求,这个代理给你结果。这样就叫做复用性I/O。这种内核早期的调用就叫做select(),还有种是poll()这两种区别不大。这两个是两个公司发明的,其中一个公司看select组件挺受别人欢迎的就山寨了一个。 select是有限制的最多只能接受1024个请求并发。你要想更多只能改内核源码,但你如果改内核源码的话可能性能还会下降。当用户请求进来的时候主进程接待分给其他子进程响应最多只能1024个,再多就超出上限拒绝服务了。这种模式还是阻塞的,但它不是阻塞自己本身上,而是阻塞在代理人上(select)。 当你发起一个IO请求的时候状态是阻塞的,这个阻塞不是阻塞在自己的调用上,而是阻塞在select上。因为select是内核中复用型I/O代理。 当你发起I/O调用的时候,数据要从磁盘到内核内存。这个时候我们调用是被阻塞的,这个时候阻塞不是阻塞在内核的I/O调用上,而是阻塞select上。这个时候select还能接受其他请求,这是最大的好处,因为他能接收其他信号上面。

他不是在性能上有提升,因为他还是阻塞的。只是他能处理其他请求。

事件驱动型I/O

当请求者发I/O请求的时候,被调用者会告诉你我知道了,你该干嘛就干嘛去。 例子:当你去叫面的时候,老板告诉你大概需要10分钟你该干嘛干嘛。你干完自己的事情的时候,去端面的时候你就是取数据了。这个时候就是你能并行运行的原因。

当这个用在web服务器上,就比如一个用户向你提交请求了。你向内核要数据,内核告诉你我知道了你该干嘛,干嘛去。这个时候你就能去处理其他用户的请求了。这就是一个进程能处理多个请求的原因。当然这个并不是说性能一定好,当然他比阻塞或者盲等待肯定有优势的。因为当你去从内核取数据当进程内存中的时候还是阻塞的。有了事件驱动型I/O就使一个进程能处理多个请求了,当然事件驱动型I/O第二个阶段还是阻塞的。

在看事件驱动型I/O当你一个请求过来的时候,系统告诉你该干嘛干嘛去。这个时候第二个请求过来了,系统告诉第二个请求我知道了你干嘛干嘛去。这个时候进程1的请求数据好了,告诉你过来拿数据吧,这个时候进程二的数据也好了也要告诉你过来拿数据吧。你需要知道一点当内核通知你拿数据的时候,你一段时间不过来拿,这个信号是会消失的。所以这时候需要讲到事件驱动通知的两种机制。 通知: 水平触发:多次通知,就是通知你一次你没响应,我就再通知你。这就很浪费系统资源了 边缘触发:所谓边缘触发就是我通知你一次你没响应,我就将这个通知事件交给回调函数,让调用者自行来获取,或者你可以这么理解我将资源放在某处。你可以自己过来找我要的。简单理解就是面好了我电话一遍遍通知你是水平触发,如果我电话通知你了,然后你没响应,我将面放到后厨,你自己也知道我电话通知你了。你自己明白你会去后厨拿的。

异步I/O模型

当调用者发送请求的时候,内核告诉你请求收到了,你该干嘛就去干嘛。这个时候内核默默的完成两个步骤后就告诉你OK了。 所以web服务器正确步骤是这样的,当用户过来请求资源的时候,内核自己完成这两个步骤从磁盘到内核空间,在到进程空间,这个时候进程就立即打包响应报文给客户端。我们httpd的event模型就是事件驱动型IO,后来我们httpd2.4以后也支持异步I/O了。这个异步模型大大提升了系统性能,他的好处让一个进程能处理多个请求,我们的进程或者内存通常会把常用的资源放在缓存中,当你有两个请求同样的数据的时候,这个数据静态的并不敏感,我们的系统能够直接响应,这对性能的提升来说可想而知

nginx从刚开始设计的时候就是用的事件驱动型IO,它同时也支持异步I/O。它还有种机制是内存映射

点赞
收藏
评论区
推荐文章
5种I/O模型
阻塞I/O(blockingI/O)非阻塞I/O(nonblockingI/O)同步I/O(synchronousI/O)or多路复用I/O(multiplexingI/O)异步I/O(asynchronousI/O)信号驱动I/O(signaldrivenI/O)1.阻塞I/O:第1阶段:内核准备数据,进程阻塞第2阶段:拷贝数据(
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
IO模型(BIO,NIO,AIO)及其区别
BIO:同步阻塞IONIO:同步非阻塞IOAIO:异步非阻塞IO先弄清楚同步、异步,阻塞、非阻塞概念。io操作分为两部分,发起io请求,和io数据读写。阻塞、非阻塞主要是针对线程发起io请求后,是否立即返回来定义的,立即返回称为非阻塞io,否则称为阻塞io。同步、异步主要针对io数据读写来定义的,读写数据过程中不阻塞线程称为异步io
Stella981 Stella981
3年前
Linux网络IO模型
同步和异步,阻塞和非阻塞_同步和异步_关注的是结果消息的通信机制同步:同步的意思就是调用方需要主动等待结果的返回异步:异步的意思就是不需要主动等待结果的返回,而是通过其他手段比如,状态通知,回调函数等。_阻塞和非阻塞_主要关注的是等待结果返回调用方的状态阻塞:是指
Wesley13 Wesley13
3年前
BIO、NIO、AIO、多路复用IO的区别(图解)
原文地址:blog.csdn.net/lzb348110175/article/details/98941378学习之前,我们先来了解一下IO模型:    ①同步阻塞IO(BlockingIO):即传统的IO模型。    ②同步非阻塞IO(NonblockingIO):默认创建的socket都是阻塞的,非阻塞
Wesley13 Wesley13
3年前
NIO高并发基础
NIO高并发是jdk1.4出现的新的流.NIONewIO同步式非阻塞式IOBIOBlockingIO同步式阻塞式IOUDP/TCPAIOAsynchronousIO异步式非阻塞IOjdk1.8BIO的缺点1.会产生阻塞行为receive/accept/connect/r
Wesley13 Wesley13
3年前
Java的BIO,NIO,AIO
  Java中的IO操作可谓常见。在Java的IO体系中,常有些名词容易让人困惑不解。为此,先通俗地介绍下这些名词。  1什么是同步?  2什么是异步?  3什么是阻塞?  4什么是非阻塞?  5什么是同步阻塞?  6什么是同步非阻塞?  7什么是异步阻塞?  8
Wesley13 Wesley13
3年前
NIO
1、简介1.1Java中的IO介绍1.BIO:BlockingIO,同步式阻塞式IO,即传统的IO,是java中最早期的流2.NIO:NonBlockingIO,又称NewIO,同步式非阻塞IO,是JDK1.4提供的流3.AIO:AsynchronousIO,异步是非阻塞IO,可以认为是NIO的二代版
Stella981 Stella981
3年前
Netty学习之IO模型
目录1.1同步、异步、阻塞、非阻塞  同步VS异步    同步    异步  阻塞VS非阻塞    阻塞    非阻塞  举例    1)同步阻塞    2)同步非阻塞    3)异步阻塞    4)异步非阻塞1.2Li
Stella981 Stella981
3年前
Linux的五种IO模型?
IO的同步、异步、阻塞、非阻塞同步、异步同步(synchronous):A调用B,B立刻处理A的请求(即使C紧接着调用B),并把最终结果返回给A。异步(asynchronous):A调用B,B立刻反馈A,仅是状态,并非最终结果。B处