I/O
模型
Richard Stevens在UNIX Network Programming
中讲述了五种I/O
模型
Blocking IO
Nonblocking IO
IO multiplexing
Signal driven IO
Asynchronous IO
而本文也是基于这五种I/O
模型,以及交叉着同步与异步&阻塞与非阻塞的概念。但在探讨I/O
模型之前,先要了解一下I/O
模型发生的对象和步骤。
对于一个文件I/O
的操作(这里以read
为例子),会涉及到两个对象:
- 一个是调用这个
I/O
的进程process
- 另外一个就是系统内核
kernel
当一个read
操作发生时,会经历两个阶段
- 进程等待内核数据准备(Waiting for the data to be ready)
- 将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)
Blocking IO
(阻塞IO)
在默认情况下,所有的IO
操作都是Blocking io
,流程如上图所示,步骤为:
- 应用进程(application process) 调用了
recvfrom
这个系统调用 - 然后内核(kernel)开始了
IO
的第一个阶段:准备数据。在内核准备数据期间,应用进程是一直阻塞的。(Waiting for the data to be ready) - 内核准备好数据之后,把数据从内核
copy
到应用内存。在内核copy
数据期间,应用进程依然是一直阻塞的。(Copying the data from the kernel to the process) - 内核返回结果,应用进程才解除block的状态,重新继续执行
Blocking IO
的特点就是在IO
执行的两个阶段都阻塞了,而Blocking IO
整个过程也是同步模型,所以Blocking IO
可以叫做同步阻塞IO
non-blocking IO
(非阻塞IO)
Non-blocking IO
与Blocking IO
不同点在于不断的查询数据是否准备好,如上图所示,流程为:
- 应用进程(application process) 调用了
recvfrom
这个系统调用 - 内核告诉应用进程,数据还没有准备好
- 应用进程发现数据没有准备好,不停的调用
recvfrom
这个系统调用,内核在数据没有准备好的情况下不停的告诉应用进程数据没有准备好。 - 内核准备数据。这个过程中,应用进程没有阻塞,因为它在不停的调用!(Waiting for the data to be ready)
- 在应用进程不停的调用中,恰好这次内核把数据准备好了,然后内核把数据copy到应用进程内存。在内核copy数据期间,应用进程是一直阻塞的。(Copying the data from the kernel to the process)
- 内核返回结果,应用进程解除
block
的状态,重新继续执行
Non-Blocking IO
模型中,数据准备阶段并没有阻塞,因为应用进程不断的查询内核数据是否准备完毕,并没有被阻塞,实际上应用进程可以在这时干其他事情。在数据复制阶段阻塞。
Non-blocking IO
模型就不能理解为同步非阻塞模式了,但是也不能理解为异步非阻塞模式,算是同步和异步的一个混合体。
IO multiplexing
(多路复用)
- 应用进程(application process) 调用了
select
这个系统调用 - 内核开始准备数据。在内核准备数据期间,应用进程是一直阻塞的。(Waiting for the data to be ready)
- 内核告诉应用进程数据准备好了
- 应用进程(application process) 调用了
recvfrom
这个系统调用 - 内核把数据copy到应用进程内存。在内核copy数据期间,应用进程是一直阻塞的。(Copying the data from the kernel to the process)
- 内核返回结果,应用进程解除
block
的状态,重新继续执行
优缺点
- 当用户进程调用了
select
,内核监视这个IO
请求 - 当N个用户进程调用了
select
,内核监视N
个IO
请求 - 有一个用户进程的
IO
数据准备好了,内核告诉该用户进程数据准备好了,来取吧 - 所以优点就在于内核可以多监视更多的
IO
请求,可以同时处理多个connection
(多说一句。所以,如果处理的连接数不是很高的话,使用select/epoll
的web server
不一定比使用multi-threading + blocking IO
的web server
性能更好,可能延迟还更大。select/epoll
的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。) - 在
IO multiplexing Model
中,如上图所示,整个用户的process
其实是一直被block
的,只不过process
是被select
这个函数block
,而不是被socket IO
请求给block
。这句很重要。 - 实际中,对于每一个
socket
,一般都设置成为non-blocking
,轮训的时机设计好,才能体现出该IO
设计模型的优势。
Signal driven I/O
(信号IO)
- 应用进程发起一个信号,告诉内核说我需要什么文件,然后立马返回
- 内核准备数据。应用进程该干嘛干嘛,不会阻塞。
- 内核准备好数据,告诉应用进程来取数据
- 应用进程请求取数据
- 内核把数据复制到应用进程。应用进程阻塞。
- 返回数据
Asynchronous I/O(异步非阻塞)
- 应用进程发起一个信号,告诉内核说我需要什么文件,然后立马返回
- 内核准备数据。应用进程该干嘛干嘛,不会阻塞。
- 内核把数据
copy
到应用进程内存。应用进程该干嘛干嘛,不会阻塞。 - 返回数据
总结
Blocking I/O
,数据准备、数据copy
全阻塞,同步阻塞IONon-blocking I/O
,数据准备不阻塞,数据copy
阻塞,非阻塞IOI/O multiplexing
,数据准备阻塞,数据copy
阻塞,多路复用IO,优点可以支持更多IO请求Signal driven I/O (SIGIO)
,数据准备不阻塞,数据copy
阻塞,异步阻塞IOAsynchronous I/O
,数据准备、数据copy
全部阻塞。异步非阻塞IO