五种I/O 模式——阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/O

五种I/O 模式——阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/O

五种I/O 模式:
【1】        阻塞 I/O           (Linux下的I/O操作默认是阻塞I/O,即open和socket创建的I/O都是阻塞I/O)
【2】        非阻塞 I/O        (可以通过fcntl或者open时使用O_NONBLOCK参数,将fd设置为非阻塞的I/O)
【3】        I/O 多路复用     (I/O多路复用,通常需要非阻塞I/O配合使用)
【4】        信号驱动 I/O    (SIGIO)
【5】        异步 I/O

一般来说,程序进行输入操作有两步:
1.等待有数据可以读
2.将数据从系统内核中拷贝到程序的数据区。

对于sock编程来说:

第一步:   一般来说是等待数据从网络上传到本地。当数据包到达的时候,数据将会从网络层拷贝到内核的缓存中;

第二步:   是从内核中把数据拷贝到程序的数据区中。

阻塞I/O模式                            //进程处于阻塞模式时,让出CPU,进入休眠状态
        阻塞 I/O 模式是最普遍使用的 I/O 模式。是Linux系统下缺省的IO模式。

大部分程序使用的都是阻塞模式的 I/O 。

一个套接字建立后所处于的模式就是阻塞 I/O 模式。(因为Linux系统默认的IO模式是阻塞模式)

对于一个 UDP 套接字来说,数据就绪的标志比较简单:
(1)已经收到了一整个数据报
(2)没有收到。
而 TCP 这个概念就比较复杂,需要附加一些其他的变量。

一个进程调用 recvfrom  ,然后系统调用并不返回知道有数据报到达本地系统,然后系统将数据拷贝到进程的缓存中。 (如果系统调用收到一个中断信号,则它的调用会被中断)

我们称这个进程在调用recvfrom一直到从recvfrom返回这段时间是阻塞的。当recvfrom正常返回时,我们的进程继续它的操作。

非阻塞模式I/O                           //非阻塞模式的使用并不普遍,因为非阻塞模式会浪费大量的CPU资源。
       当我们将一个套接字设置为非阻塞模式,我们相当于告诉了系统内核: “当我请求的I/O 操作不能够马上完成,你想让我的进程进行休眠等待的时候,不要这么做,请马上返回一个错误给我。”
      我们开始对 recvfrom 的三次调用,因为系统还没有接收到网络数据,所以内核马上返回一个 EWOULDBLOCK的错误。

第四次我们调用 recvfrom 函数,一个数据报已经到达了,内核将它拷贝到我们的应用程序的缓冲区中,然后 recvfrom 正常返回,我们就可以对接收到的数据进行处理了。
      当一个应用程序使用了非阻塞模式的套接字,它需要使用一个循环来不听的测试是否一个文件描述符有数据可读(称做 polling(轮询))。应用程序不停的 polling 内核来检查是否 I/O操作已经就绪。这将是一个极浪费 CPU资源的操作。这种模式使用中不是很普遍。

例如:

对管道的操作,最好使用非阻塞方式!

I/O多路复用                             //针对批量IP操作时,使用I/O多路复用,非常有好。

在使用 I/O 多路技术的时候,我们调用 select()函数和 poll()函数或epoll函数(2.6内核开始支持),在调用它们的时候阻塞,而不是我们来调用 recvfrom(或recv)的时候阻塞。
       当我们调用 select函数阻塞的时候,select 函数等待数据报套接字进入读就绪状态。当select函数返回的时候, 也就是套接字可以读取数据的时候。 这时候我们就可以调用 recvfrom函数来将数据拷贝到我们的程序缓冲区中。
        对于单个I/O操作,和阻塞模式相比较,select()和poll()或epoll并没有什么高级的地方。

而且,在阻塞模式下只需要调用一个函数:

读取或发送函数。

在使用了多路复用技术后,我们需要调用两个函数了:

先调用 select()函数或poll()函数,然后才能进行真正的读写。

多路复用的高级之处在于::

它能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,select()函数就可以返回。

IO 多路技术一般在下面这些情况中被使用:
1、当一个客户端需要同时处理多个文件描述符的输入输出操作的时候(一般来说是标准的输入输出和网络套接字),I/O 多路复用技术将会有机会得到使用。
2、当程序需要同时进行多个套接字的操作的时候。
3、如果一个 TCP 服务器程序同时处理正在侦听网络连接的套接字和已经连接好的套接字。
4、如果一个服务器程序同时使用 TCP 和 UDP 协议。
5、如果一个服务器同时使用多种服务并且每种服务可能使用不同的协议(比如 inetd就是这样的)。

异步IO模式有::

1、信号驱动I/O模式

2、异步I/O模式

信号驱动I/O模式                                                   //自己没有用过。

我们可以使用信号,让内核在文件描述符就绪的时候使用 SIGIO 信号来通知我们。我们将这种模式称为信号驱动 I/O 模式。

为了在一个套接字上使用信号驱动 I/O 操作,下面这三步是所必须的。
(1)一个和 SIGIO信号的处理函数必须设定。
(2)套接字的拥有者必须被设定。一般来说是使用 fcntl 函数的 F_SETOWN 参数来
进行设定拥有者。
(3)套接字必须被允许使用异步 I/O。一般是通过调用 fcntl 函数的 F_SETFL 命令,O_ASYNC为参数来实现。

虽然设定套接字为异步 I/O 非常简单,但是使用起来困难的部分是怎样在程序中断定产生 SIGIO信号发送给套接字属主的时候,程序处在什么状态。

1.UDP 套接字的 SIGIO 信号                    (比较简单)
在 UDP 协议上使用SIGIO 非常简单.这个信号将会在这个时候产生:

1、套接字收到了一个数据报的数据包。
2、套接字发生了异步错误。
        当我们在使用 UDP 套接字异步 I/O 的时候,我们使用 recvfrom()函数来读取数据报数据或是异步 I/O 错误信息。
2.TCP 套接字的 SIGIO 信号                      (因为复杂,实际一般用的是socket的异步IO)
          不幸的是,SIGIO 几乎对 TCP 套接字而言没有什么作用。因为对于一个 TCP 套接字来说,SIGIO 信号发生的几率太高了,所以 SIGIO 信号并不能告诉我们究竟发生了什么事情。

在 TCP 连接中, SIGIO 信号将会在这个时候产生:
l  在一个监听某个端口的套接字上成功的建立了一个新连接。
l  一个断线的请求被成功的初始化。
l  一个断线的请求成功的结束。
l  套接字的某一个通道(发送通道或是接收通道)被关闭。
l  套接字接收到新数据。
l  套接字将数据发送出去。

l  发生了一个异步 I/O 的错误。

一个对信号驱动 I/O 比较实用的方面是 NTP(网络时间协议 Network Time Protocol)服务器,它使用 UDP。这个服务器的主循环用来接收从客户端发送过来的数据报数据包,然后再发送请求。对于这个服务器来说,记录下收到每一个数据包的具体时间是很重要的。

因为那将是返回给客户端的值,客户端要使用这个数据来计算数据报在网络上来回所花费的时间。图 6-8 表示了怎样建立这样的一个 UDP 服务器。

异步I/O模式             //比如写操作,只需用写,不一定写入磁盘(这就是异步I/O)的好处。异步IO的好处效率高。
      当我们运行在异步 I/O 模式下时,我们如果想进行 I/O 操作,只需要告诉内核我们要进行 I/O 操作,然后内核会马上返回。具体的 I/O 和数据的拷贝全部由内核来完成,我们的程序可以继续向下执行。当内核完成所有的 I/O 操作和数据拷贝后,内核将通知我们的程序。
异步 I/O 和  信号驱动I/O的区别是:
        1、信号驱动 I/O 模式下,内核在操作可以被操作的时候通知给我们的应用程序发送SIGIO 消息。

2、异步 I/O 模式下,内核在所有的操作都已经被内核操作结束之后才会通知我们的应用程序。

时间: 2024-10-16 22:39:53

五种I/O 模式——阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/O的相关文章

为何 epoll 的 ET 模式一定要设置为非阻塞IO

ET模式下每次write或read需要循环write或read直到返回EAGAIN错误.以读操作为例,这是因为ET模式只在socket描述符状态发生变化时才触发事件,如果不一次把socket内核缓冲区的数据读完,会导致socket内核缓冲区中即使还有一部分数据,该socket的可读事件也不会被触发根据上面的讨论,若ET模式下使用阻塞IO,则程序一定会阻塞在最后一次write或read操作,因此说ET模式下一定要使用非阻塞IO 原文地址:https://www.cnblogs.com/develo

python(十)下:事件驱动与 阻塞IO、非阻塞IO、IO多路复用、异步IO

上节的问题: 协程:遇到IO操作就切换. 但什么时候切回去呢?怎么确定IO操作完了? 一.事件驱动模型介绍 通常,我们写服务器处理模型的程序时,有以下几种模型: (1)每收到一个请求,创建一个新的进程,来处理该请求: (2)每收到一个请求,创建一个新的线程,来处理该请求: (3)每收到一个请求,放入一个事件列表,让主进程通过非阻塞I/O方式来处理请求 第三种就是协程.时间驱动的方式,一般普遍认为第(3)种方式是大多数网络服务器采用的方式 论事件驱动模型 在UI编程中,,常常要对鼠标点击进行相应,

理论铺垫:阻塞IO、非阻塞IO、IO多路复用/事件驱动IO(单线程高并发原理)、异步IO

完全来自:http://www.cnblogs.com/alex3714/articles/5876749.html 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. 本文讨论的背景是Linux环境下的network IO. 一 概念说明 在进行解释之前,首先要说明几个概念:- 用户空间和内核空间- 进程切换- 进程的阻塞- 文件描述符- 缓存 I/O 用户空间与内核空间 现在操作系统都是采用虚拟存储器,

阻塞IO、非阻塞IO、IO多路复用、同步IO、异步IO 的理论

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

同步IO,异步IO,阻塞IO,非阻塞IO的联系与区别

转载 POSIX 同步IO.异步IO.阻塞IO.非阻塞IO,这几个词常见于各种各样的与网络相关的文章之中,往往不同上下文中它们的意思是不一样的,以致于我在很长一段时间对此感到困惑,所以想写一篇文章整理一下. POSIX(可移植操作系统接口)把同步IO操作定义为导致进程阻塞直到IO完成的操作,反之则是异步IO 按POSIX的描述似乎把同步和阻塞划等号,异步和非阻塞划等号,但是为什么有的人说同步IO不等于阻塞IO呢?先来说说几种常见的IO模型吧. IO模型 这里统一使用Linux下的系统调用recv

并发编程 - IO模型 - 1.io模型/2.阻塞io/3.非阻塞io/4.多路复用io

1.io模型提交任务得方式: 同步:提交完任务,等结果,执行下一个任务 异步:提交完,接着执行,异步 + 回调 异步不等结果,提交完任务,任务执行完后,会自动触发回调函数同步不等于阻塞: 阻塞:遇到io,自己不处理,os会抢走cpu ,解决办法:监测到io,gevent切换到其他任务,类似欺骗os 非阻塞:cpu 运行 IO分类: 1.阻塞IO blocking IO 2.非阻塞IO nonblocking IO 3.IO多路复用 IO multiplexing 4.信号驱动IO signal

阻塞IO、非阻塞IO的区别

1.类与类之间的关系:依赖,实现,泛化(继承),关联,组合,聚合. 1)依赖(虚线):一个类是 另一个类的函数参数 或者 函数返回值. 2)实现(实线加小圆):对纯虚函数类(抽象类)的实现. 3)继承 即 泛化(实线加空心三角形,从子类指向父类):表示一个类与另一个类之间的继承关系: 4)关联(实线):一个类是另一个类的成员变量. 5)聚合(菱形加实线):整体和部分的关系.不太紧密的(如:汽车与发动机,汽车可以选择各种型号的发动机) 6)组合(实心菱形加实线):生命体整体与部分的关系.紧密的关系

网络编程之IO模型——非阻塞IO

网络编程之IO模型--非阻塞IO 非阻塞IO(non-blocking IO) Linux下,可以通过设置socket使其变为non-blocking.当对一个non-blocking socket执行读操作时,流程是这个样子: 从图中可以看出,当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error.从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果.用户进程判断结果是一个error时,它就

java 多线程阻塞队列 与 阻塞方法与和非阻塞方法

Queue是什么 队列,是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的.无论使用哪种排序方式,队列的头都是调用remove()或poll()移除元素的.在FIFO队列中,所有新元素都插入队列的末尾.队列都是线程安全的,内部已经实现安全措施,不用我们担心 Queue中的方法 Queue中的方法不难理解,6个,每2对是一个也就是总共3对.看一下JDK API就知道了: 注意一点就好,Queue通常不允许插入Null,尽管某些实现(比如Link

11.python并发入门(part14阻塞I/O与非阻塞I/O,以及引入I/O多路复用)

一.初步了解什么是I/O模型. 1.回顾,用户态与内核态. 操作系统位于应用程序和硬件之间,本质上是一个软件,它由内核以及系统调用组成. 内核:用于运行于内核态,主要作用是管理硬件资源. 系统调用:运行与用户态,为应用程序提供系统调用的接口. 操作系统的核心,就是内核,内核具有访问底层硬件设备的权限,为了保证用户无法直接对内核进行操作,并且保证内核的安全,所以就划分了用户空间和内核空间. 2.回顾进程切换. 如果说要实现进程之间的切换,那么进程需要有能力挂起,有能力回复,这样才叫切换. 进程与进