操作系统IO模型

操作系统IO模型

声明:如下内容是根据APUE和mycat两本著作中关于I/O模式的一些内容加上自己的一些理解整理而成,仅供学习使用。

本节内容

  1. UNIX下可用的五种I/O模型
  2. 三种I/O模型
  3. Reactor和Proactor模式

UNIX下可用的五种I/O模型

  1. 阻塞式I/O
  2. 非阻塞式I/O
  3. I/O复用(select和poll)
  4. 信号驱动式I/O(SIGIO)
  5. 异步I/O(POSIX的aio_系列函数)

其中,2,3,4又可以总结成一类叫做非阻塞同步型,他们的实现方式上有一些差别。

下面是5种I/O模型展示:

  1. 阻塞式I/O

默认情况下,所有套接字都是阻塞式的,进程调用recvfrom之后到数据成功返回之前,这段时间都是阻塞的。 

2. 非阻塞式I/O

进程在调用recvfrom的时候,如果数据没有准备好,那么返回一个EWOULDBLOCK错误给进程,这时进程并不进入休眠状态,而是循环调用recvform直到数据准备完毕之后并返回数据处理成功的消息。当循环调用recvfrom这个动作,我们称之为轮询(polling),这个过程中将会大量消耗CPU的时间。在日常使用中这种模型并不常见。

3. I/O复用(select和poll)

进程使用I/O复用的时候,调用select或poll,阻塞在这两个系统调用的某一个之上,而不是阻塞在真正的I/O系统调用之上。 进程阻塞在select调用之上,直到资源已经准备好时,返回套接字可读,之后进程才调用recvfrom去获取数据。这种方式看起来和非阻塞式I/O模型对比并没什么优势,但是使用select的优势在于我们可以等待多个文件描述符就绪。

其实select内部实现机制也就是使用轮询去检查多个文件描述符是否准备就绪,只要有一个文件描述符准备就绪,那么就通知进程去处理该文件。

与I/O复用密切相关的另一种I/O模型是在多线程中使用阻塞式I/O.这种模型与I/O复用模型很相似,但它没有使用select阻塞在多个文件描述符上,而是使用多个线程(每个文件描述符一个线程),这样每个线程都可以自由的调用诸如recvfrom之类的阻塞式I/O系统调用了。(PS:或许这就是我之前看socketserver源码中使用select没理解的地方吧。。。)

4. 信号驱动式I/O(SIGIO)

进程在最开始时使用sigaction发送系统调用,之后立即返回调用结果,这时进程处于非阻塞状态,去处理其他事情,当内核在描述符就绪时发送SIGIO信号通知进程,进程再使用recvfrom读取数据。该模型好处在于等待数据准备好这段时间,进程不会处于阻塞状态中。 

5. 异步I/O(POSIX的aio_系列函数)

这种模型的工作机制是进程告诉内核要做某个操作,并让内核在完成整个操作之后通知我们。这种方式和前面的信号驱动式I/O区别是信号驱动I/O由内核通知我们何时可以启动I/O操作,而异步I/O模型是由内核完成了所有操作之后告诉我们I/O操作完成了。

在linux中实现这种机制的方式是epoll,在2.6x以后的内核中才支持这种方式。。。

五种I/O模型的比较

前面四种I/O模型都在处理真正的I/O时是阻塞模式,只有最后一种是真正的异步I/O模型,和POSIX定义的异步I/O匹配。

三种 IO 类型

系统 I/O 可分为阻塞型, 非阻塞同步型及非阻塞异步型.

阻塞型 I/O 意味着控制权直接调用操作结束了才会回到调用者手里. 如果调用者被阻塞了, 这段时间做不了任何其它事情. 更郁闷的是,在等待 IO 结果的时间里,调用者所在线程此时无法腾出手来去响应其它的请求,这真是太浪费资源了。拿 read()操作来说吧, 调用此函数的代码会一直僵在此处直至它所读的 socket 缓存中有数据到来.

相比之下,非阻塞同步是会立即返回控制权给调用者的。调用者不需要等等,它仅调用的函数获取两种结果:要么此次调用成功进行了;要么系统返回错误标识告诉调用者当前资源不可用,你再等等或者再试度看吧。比如 read()操作, 如果当前 socket 无数据可读,则立即返回 EWOULBLOCK/EAGAIN,告诉调用 read()者“ 数据还没准备好,你稍后再试” 。

在非阻塞异步调用中,稍有不同。调用函数在立即返回时,还告诉调用者,这次请求已经开始了。系统会使用另外的资源或者线程来完成这次调用操作,并在完成的时候知会调用者(比如通过回调函数)。拿 Windows的 ReadFile()或者 POSIX 的 aio_read()来说,调用它之后,函数立即返回,操作系统在后台同时开始读操作。

在以上三种 IO 形式中,理论上,非阻塞异步是性能最高、伸缩性最好的。

同步和异步是相对于应用和内核的交互方式而言的,同步需要主动去询问,而异步的时候内核在 IO事件发生的时候通知应用程序,而阻塞与非阻塞仅仅是系统在调用系统调用的时候函数的实现方式而已。

Reactor和Proactor模式

NIO 和 AIO 分别对应的两种设计模式:Reactor 和 Proactor

一般情况下,I/O 复用机制需要事件分享器(event demultBossiplexor). 事件分享器的作用,即将那些读写事件源分发给各读写事件的处理者,就像送快递的在楼下喊: 谁的什么东西送了, 快来拿吧。开发人员在开始的时候需要在分享器那里注册感兴趣的事件,并提供相应的处理者(event handlers),或者是回调涵数; 事件分享器在适当的时候会将请求的事件分发给返读 handler 或者回调涵数。

涉及到事件分享器的两种模式称为:Reactor和Proactor.

Reactor 模式是基于同步 I/O 的,而 Proactor 模式是和异步 I/O 相关的. 在 Reactor 模式中,事件分离者等待某个事件或者应用或操作的状态发生(比如文件描述符可读写,或者是 socket 可读写),事件分离者就把返个事件传给事兇注册的事件处理涵数或者回调涵数,由后者来做实际的读写操作。

而在 Proactor 模式中,事件处理者(或者代由事件分离者发起)直接发起一个异步读写操作(相当于请求),而实际的工作是由操作系统来完成的。发起时,需要提供的参数包括用于存放读到数据的缓存区,读的数据大小,或者用于存放外发数据的缓存区,以及这个请求完后的回调涵数等信息。事件分离者得知了这个请求,它默默等待这个请求的完成,然后转发完成事件给相应的事件处理者或者回调。举例来该,在 Windows 上事件处理者投递了一个异步 IO 操作(称有 overlapped 的技术),事件分离者等 IOCompletion 事件完成. 返种异步模式的典型实现是基于操作系统底层异步 API 的,所仌我们可称之为“ 系统级别” 的或者“ 真正意义上” 的异步,因为具体的读写是由操作系统代劳的。

Reactor 不 Proactor 两种模式的场景区别:

下面是 Reactor 的做法:

1. 等待事件响应 (Reactor job)

2. 分发 “Ready-to-Read” 事件给用户句柄 ( Reactor job)

3. 读数据 (user handler job)

4. 处理数据( user handler job)

下面再来看看真正意义的异步模式 Proactor 是如何做的:

1. 等待事件响应 (Proactor job)

2. 读数据 (Proactor job)

3. 分发 “Read-Completed” 事件给用户句柄 (Proactor job)

4. 处理数据(user handler job)

仅上面可以看出,Reactor 和 Proactor 模式的主要区别就是真正的读取和写入操作是由谁来完成的,Reactor 中需要应用程序自己读取或写入数据,而 Proactor 模式中,应用程序不需要进行实际的读写过程,它只需要从缓存区读取或者写入即可,操作系统会读取缓存区或者写入缓存区到真正的 IO 设备。

最后结合下面的两张图更容易理解:

时间: 2024-10-05 02:47:24

操作系统IO模型的相关文章

走入计算机的第三十九天(python终结篇之IO模型)

一.IO模型 1.IO模型分类 1.阻塞IO--------blocking IO 2.非阻塞IO------nonblocking IO 3. 多路复用IO------- multiplexing 4.信号驱动IO-------signal driven IO (工作中不会使用到,只是作为了解) 5.异步IO------- asynchronous IO 2.通常情况下IO默认操作分为两个阶段(默认都是阻塞IO) 1.准备等待数据阶段,相当于请求操作系统是否有数据发送过来(调用IO操作). 2

IO模型介绍 以及同步异步阻塞非阻塞的区别

阻塞:用户进程访问数据时,如果未完成IO,等待IO操作完成或者进行系统调用来判断IO是否完成非阻塞:用户进程访问数据时,会马上返回一个状态值,无论是否完成 同步:用户进程发起IO(就绪判断)后,轮询内核状态异步:用户进程发起IO后,可以做其他事情,等待内核通知 介绍一下IO模型 网络IO模型和文件IO模型是一样的,上图是IO的5种模型,包括阻塞IO.非阻塞IO.多路复用IO.信号驱动的IO.异步IO. 一次IO包括两个过程,内核数据准备 .把数据从内核空间copy到用户空间. 1.阻塞IO(re

5种网络IO模型(有图,很清楚)

同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出的答案都可能不同,比如wiki,就认为asynchronous IO和non-blocking IO是一个东西.这其实是因为不同的人的知识背景不同,并且在讨论这个问题的时候上下文(context)也不相同.所以,为了更好的回答这个问题,我先限定一下本文的上下文. 本文讨论的背景是Linux环境下的n

高性能IO模型浅析(转)

转自:http://www.cnblogs.com/fanzhidongyzby/p/4098546.html 是我目前看到的解释IO模型最清晰的文章,当然啦,如果想要详细的进一步了解还是继续啃蓝宝书吧. 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK.注意这里所说的NIO

IO模型-java版

描述IO,我们需要从两个层面: 编程语言 实现原理 底层基础 从编程语言层面 BIO | NIO | AIO 以Java的角度,理解,linux c里也有AIO的概念(库),本文只从Java角度入手. BIO,同步阻塞式IO,简单理解:一个连接一个线程 NIO,同步非阻塞IO,简单理解:一个请求一个线程 AIO,异步非阻塞IO,简单理解:一个有效请求一个线程 BIO 在JDK1.4之前,用Java编写网络请求,都是建立一个ServerSocket,然后,客户端建立Socket时就会询问是否有线程

Linux五种IO模型性能分析

socket阻塞与非阻塞,同步与异步 作者:huangguisu 1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式:同步:      所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回.也就是必须一件一件事做,等前一件做完了才能做下一件事. 例如普通B/S模式(同步):提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事 异步:      异步的概念和同步相对

聊聊 Linux 中的五种 IO 模型

本文转载自: http://mp.weixin.qq.com/s?__biz=MzAxODI5ODMwOA==&mid=2666538919&idx=1&sn=6013c451b5f14bf809aec77dd5df6cff&scene=21#wechat_redirect 上一篇<聊聊同步.异步.阻塞与非阻塞>已经通俗的讲解了,要理解同步.异步.阻塞与非阻塞重要的两个概念点了,没有看过的,建议先看这篇博文理解这两个概念点.在认知上,建立统一的模型.这样,大家在

高性能IO模型浅析

服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK.注意这里所说的NIO并非Java的NIO(New IO)库. (3)IO多路复用(IO Multiplexing):即经典的Reactor设计模式,有时也称为异步阻塞IO,Java中的Selector和Linux中的epoll

python学习笔记(IO模型)

1.IO模型介绍: io模型一般有五种: * blocking IO         * nonblocking IO         * IO multiplexing         * signal driven IO         * asynchronous IO 但是 signal driven IO(信号驱动IO)在实际中并不常用,所以只介绍其他四中IO模型 另当IO发生时涉及的对象和步骤.对于一个network IO (这里我们以read举例),它会涉及到两个系统对象,一个是调