Linux五种I/O模型

来源:互联网 发布:刘嘉玲被强奸知乎 编辑:程序博客网 时间:2024/06/05 04:54

1. 概念浅析

在进行网络编程时,常常会碰到阻塞、非阻塞、同步、异步四种调用方式:

  • 同步:一个函数调用在得到结果之前就一定不返回,即事情必须要一件一件地做,做了上一件才能进行下一件。最普通的B-S模式即为同步的,提交请求->等待服务器处理->处理完毕返回。等待的时间之内浏览器不能干任何事。

  • 异步:当一个异步调用开始之后,调用者并不能马上得到调用的结果。而当这个调用处理结束之后,会有通知信息来通知调用者调用已经完成了。例如,ajax的请求过程,请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕。

  • 阻塞:阻塞指的是在调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,cpu不会给线程分配时间片,即线程暂停运行),函数也只有在得到的结果之后才会返回。有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。 例如,我们在socket中调用recv函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消息。

  • 非阻塞: 非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

2. 阻塞模式和阻塞调用

对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但是并不是一一对应的。

阻塞对象可以有非阻塞的调用方式,我们可以通过一定的API去轮询状态,在适当的时候调用阻塞函数,就可以避免阻塞

而对于非阻塞对象,调用特殊的函数也可以进入阻塞调用。函数select就是这样的一个例子。(???)

  1. 同步,就是我调用一个函数,该函数没有结束前,我一直等结果。
  2. 异步,就是我调用一个函数,不需要知道该函数的结果,该函数出现结果之后通知我(回调通知)
  3. 阻塞,就是调用我(函数),我(函数)没有接收完数据或者没有得到结果之前,我不会返回。
  4. 非阻塞,就是调用我(函数),我(函数)立即返回,通过select通知调用者

阻塞和非阻塞是指当进程访问的数据如果尚未就绪,进程是否需要等待,简单说这相当于函数内部的实现区别, 也就是未就绪时是直接返回还是等待就绪;

而同步和异步是指访问数据的机制的区别:

  • 同步一般指主动请求并等待I/O操作完毕的方式。当数据就绪后在读写的时候必须阻塞(区别就绪与读写二个阶段,同步的读写必须阻塞);

  • 异步则指主动请求数据后便可以继续处理其它任务,随后等待I/O,操作完毕的通知,这可以使进程在数据读写时也不阻塞。(等待”通知”)

3. Linux五种IO模型

  • 阻塞I/O(blocking I/O)
  • 非阻塞I/O (nonblocking I/O)
  • I/O复用(select 和poll) (I/O multiplexing)
  • 信号驱动I/O (signal driven I/O (SIGIO))
  • 异步I/O (asynchronous I/O (the POSIX aio_functions))

其中前四种模型都是同步模型,只有最后一种模型才是异步模型

a. 阻塞I/O:

简介:进程会一直阻塞,直到数据拷贝完成

应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好。
如果数据没有准备好,则会一直等待; 数据准备好了,从内核拷贝到用户空间,IO函数返回成功指示。

阻塞I/O模型图:在调用recv()/recvfrom()函数时,发生在内核中等待数据和复制数据的过程。
这里写图片描述
例如,当调用recvfrom函数的时候,系统会检查是否数据已经准备好,如果数据已经准备好,则会将数据从系统缓冲区复制到用户空间,然后函数返回。而如果内核发现没有数据报准备好,则内核此时会等待数据,recvfrom函数也会等待数据。

阻塞的I/O模式:

  • 开发比较简单,如果希望立即做到收发数据并且数据量比较小的时候,可以使用。
  • 阻塞模式套接字的不足表现为,在大量建立好的套接字线程之间进行通信时比较困难。
  • 当使用“生产者-消费者”模型开发网络程序时,为每个套接字都分别分配一个读线程、一个处理数据线程和一个用于同步的事件,那么这样无疑加大系统的开销。
b. 非阻塞I/O:

简介:非阻塞IO通过进程反复调用IO函数(多次系统调用,并马上返回);在数据拷贝的过程中,进程是阻塞的;

我们把一个socket设置为非阻塞就是告诉内核,当所请求的I/O操作无法完成时,不要将进程睡眠,而是让函数立即返回,只不过这里返回的是一个错误代码。

这样我们的I/O操作函数将不断地测试数据是否已经准备好,如果没有准备好,继续测试,直到数据准备好为止。

在这个不断测试的过程中,会大量的占用CPU的时间。
这里写图片描述

但是,非阻塞套接字在控制建立的多个连接,在数据的收发量不均,时间不定时,明显具有优势。这种套接字在使用上存在一定难度,但只要排除了这些困难,它在功能上还是非常强大的。

I/O多路复用:

简介:

  • 主要是select和epoll;
  • 对一个I/O端口,两次调用,两次返回,比阻塞I/O并没有什么优越性;
  • 关键是能实现同时对多个IO端口进行监听;

I/O复用模型会用到select、poll、epoll函数,这几个函数也会使进程阻塞,但是和阻塞I/O所不同的的,这两个函数可以同时阻塞多个I/O操作。

而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数。
这里写图片描述

信号驱动IO

首先我们允许套接口进行信号驱动I/O,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。
这里写图片描述

http://blog.csdn.net/jay900323/article/details/18141217#t5

原创粉丝点击