I/O模型

I/O操作根据设备的不同分为很多种类型,比如网络IO、内存IO、硬盘IO,对于网络和硬盘IO它们比内存IO要慢很多,不管是哪种IO类型,这些IO操作都是由内核来完成。

在实现功能调用的时候通常会提到同步和异步的概念:

阻塞I/O:阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入睡眠状态)。函数只有在得到结果之后才会返回。

比如我们使用cat命令来查看一个文件内容,但是这个文件非常大,需要几秒钟才会打开,一旦cat命令发起为一个进程之后,接下来必须要等待这个文件装载进内存 所以在文件载入内存之前,必须把这个进程转为睡眠状态,I/O在后台自动完成。

 

I/O完成步骤:

一旦某一进程发起I/O调用之后,内核收到后立即进入响应模式,内核从磁盘中读进内核能访问到的内存空间(指的是内核独有的内存空间,而进程不能访问)

内核处理完成后则将内核内存中的数据复制到进程内存空间中,由于内核内存空间进程是不允许被访问的,因此数据被载入到内核内存空间,必须再复制才能被进程访问,这段过程为I/O完成的过程。

I/O模型

一般来讲文件I/O都是阻塞的,网络I/O有可能会使用非阻塞I/O模型

非阻塞:指在不能立刻得到结果之前,被调用函数不会阻塞当前线程,而会立刻返回,非阻塞状态属于忙等待状态,性能比较差

 

总之可以分为两段来理解:

I/O模型

如上图所示:

第一段是内核负责将数据从磁盘装载进内核内存;

第二段是内核负责将数据从内核内存复制进进出内存;

阻塞 I/O  :一旦进程发起IO调用,于是整个进程将被阻塞了,不再执行,第一段被阻塞的,第二段也是被阻塞的 直到第二段也被处理完成,那么整个系统调用才会返回结果说白了就是一步完成,如图1所示。

非阻塞I/O :一旦发起调用,内核立即返回让其稍等,内核将数据从硬盘载入到内核内存中来,这时则处于等待状态,等待数据从内核内存复制到进程内存,直到第一步完成,所以第一段是非阻塞,而第二段是阻塞的

IO多 路复用:需要调用I/O时,不会直接告知内核,而是向内核一个特殊的系统调用,使其告知哪个IO是否处理完成,这样我们的内核就可以同时处理多个I/O, 如上的例子,我们的I/O会阻塞到复用调用上,所以复用这个功能会监听每个IO是否完成,如果都同时完成则可以进行下面的操作

如果一个进程调用了多个IO(如键盘IO或硬盘IO) 如果其中某一个IO执行完成而另一个IO没有处理完成,那么这个IO是处于睡眠状态,就算另一个IO完成它也不会得知,这时IO多路复用就有意义了

常用I/O复用:

select :就是IO复用器,将请求发给select ,由select来进行调用,select还可以监控调用是否结束,一旦结束则将数据发给进程,但是最多只支持1024个同时请求而 apache本身 prefork工作模型就是基于select模型来完成的,所以限制了prefork模型最多接收进来的请求进来同时不能超过1024个,因此在一旦用户 并发请求数(在线请求数)超过1024个,apache就不再提供服务了,所以说使用select 模型的apcahe的性能很差,至少说在用户请求量非常大的情况下,apache的prefork模型情况下是应付不来的。

基 于select模式虽然实现了IO复用,也解决了多路调用的问题,但是个缺陷,多路复用本身的后半段仍是阻塞状态,只不过是阻塞在select而没有阻塞 在IO调用上,由负责扫描多个IO 使得整个系统能够完成多路I/O了 但是多了一个处理机制性能在一定程度来讲,未必是上升,有可能还会下降,于是就有了第四种模型:event-driven

 

event-driven(基于事件驱动复用机制):扫描全是全局,而这种通知只是哪个完成通知哪个,对于被调用来讲,他的任何一个调用请求执行完成才会通知给调用者,而且没被处理完成不会被通知。

本身是通过事件函数主动发起通知的,比select的调用机制要强大很多,

 

event:进程发起请求之后,进程会发起”回调 函数”意味着向内核发送信息”要发起系统调用”,内核会记录哪个进程发起的请求,于是进程处理其他请求,一旦第一段完成,内核通过毁掉函数向发起请求的进程发起通知,于是阻塞在第二阶段。虽然一个进程响应多个请求有缺陷:第二段仍然会阻塞,仍然会影响系统性能,复制的过程如果有新用户请求过来则不能接收

 

AIO:异步IO

异步IO缺陷:复制完成之后才会通知,为了增强AIO的性能研发了mmap

mmap:内存映射机制 内核将数据从磁盘装载进内核内存之后,不再复制,直接建立映射关系,进程访问的仍然是自己的内存空间,但是数据是来自于内核的。

 

基于IO模型实现的web架构:

(1)单进程模型

假如一次来5个请求,每个请求都产生一个网络IO,第一个用户请求进来,web通过io调用返回给用户,直到用户响应结束后第二个用户才能被处理。单进程模型是最简单的模型也可以理解为单线程阻塞模型

(2)多进程模型

每个用户请求到达主进程,请求到达之后 ,发现请求的是当前主机,这是则派发一个子进程来响应请求,以此类推,主进程只接受用户请求并为其派发子进程,而prefork机制是根据select函数来调用的

(进程次数切换过多的结果就是把大量的CPU资源都耗费在内核模式上,而且是白白浪费)

(3)worker模型

首先生成主进程来监听端口,从而生成多个工作子进程,每个子进程会生成多个线程来工作,请求到来时,主进程会负责从工作子进程中招一个线程来响应请求。

(4)prefork模型,上面提到了哦

 转载:http://yijiu.blog.51cto.com/433846/1348857


发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

I/O模型

什么是I/O模型,刚接触这个问题的时候,对于我这个外行人来说着实是老大难问题(我是个学汽车的)。最开始基础计算机的时候这些也没怎么讲过的,也有可能讲过,但是忘了^_^……

我是一个保守中带点随性的人,这也铸就了我的性格属于那种喜新厌旧的类型,所以,对于比较新奇的事物比较感兴趣,注意!是事物!不是八卦……恰巧的是,对于男人而言,新鲜的电子产品就像足球一样总能博得较高的关注,甚至胜过女人,这是不言而喻的。所以很长一段时间对于这类昂贵的精密产品还是比较热衷,是那种比较肤浅的热衷,仅限外观和好玩,从没仔细的探寻过其中的奥秘。

在我眼中,I/O还是停留在BIOS阶段,基本输入输出系统现在还是记得比较清楚的,显示器就是输出,键盘鼠标就输入,其他的就不知道了,可是实时证明,劳资错了,错的一塌糊涂。那么下面就说说什么是I/O模型吧>_<!!!

假设两个主机ABA(被调用方)能够提供服务,B能够通过自身运行的一个系统调用向被调用方(A)发送调用请求,A接收调用请求后,将运行结果返回给调用方(B)。这就是一个I/O

也可以这么想,我们进行一次磁盘上的read操作,请求调用由用户空间发出,由于只有内核可调用磁盘上的数据,所以,用户的请求应该先发给内核,内核去磁盘上提取相应的文件,并存储在内核内存中,再将内核内存中的数据复制一份到用户空间中。注:这里真正的I/O仅仅是内核空间向用户空间复制数据的这一段。

I/O有几种分类方法,可以分为同步(synchronous)和异步(asynchronous),同步和异步关注的是消息通知机制;也可分为阻塞(block)和非阻塞(nonblock),阻塞和非阻塞关注的是调用者等待被调用者返回调用结果时的状态。

同步:调用发出后不会立即返回,一旦返回,则返回的是最终结果;

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

阻塞:调用结果返回之前,调用者会被挂起;调用者只有在得到返回结果之后才能继续;(解释:想象成一件事情接一件事情去运行)

非阻塞:调用者在结果返回之前,不会被挂起,即调用不会阻塞调用者;(解释:几件事情允许同时运作)

根据以上的定义,接下来I/O模型就可以很好的理解了,I/O模型分为五种:

1、  阻塞式I/Oblocking I/O

2、  非阻塞式I/OnonblockingI/O

3、  复用型IO IOmultiplexing

4、  事件驱动式IOsignaldriven IO

5、  异步IOasynchronousIO

这五种到底是什么意思呢?举个例子:

1、如果一个客户端向服务器端请求一个页面,那么服务器就会加载这个页面给客户端,但是,在这个加载这期间内,服务器就不能响应其他用户请求了,直到这个页面加载完毕,才能响应其他用户请求,这就是阻塞式I/O

2、对磁盘进行read操作,其中客户端发送给内核一个请求,内核即时响应一个结果表明收到请求,然后除了真正进行I/O时,其他的时间都是在盲等待,在盲等待的时间内用户空间会反复向内核询问结果,直到I/O完成(注意:进行真正的I/O时也是阻塞式I/O)所以说,对于一些进行真正I/O时间较长时,非阻塞式I/O并不能带来性能上的提升;

3、复用型I/O,简单说来类似于LVS负载均衡的模型,通过一个类似于调度器的组件(这里叫select)将各种请求分配给后端的子进程运行,这样就可以做到同时处理N个请求,但这个数量也有上限,为1024,这也就是为什么prefork模型的最大并发量为1024个的原因了。复用型I/O也是阻塞型的,只不过阻塞在select上;

4、事件驱动式I/O,请求发送给内核后,内核会即时响应给用户空间一个信号,并且在处理完通知用户空间,这样用户空间就无需盲等待,同时,内核调用磁盘文件时也可同时响应用户控件发来的其他请求,这样就实现了单进程响应多个请求的目的。但是内核空间与用户空间真正发生I/O时依然是阻塞型I/O

5、异步I/O,用户空间发送请求给内核后,内核即时响应一个信号,然后会将其他所有事情处理完毕后通知用户空间,甚至连内核空间到用户空间的复制也是非阻塞的。

以下图做为参考:


发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注