I/O模型的一些基本概念
POSIX定义
-
同步I/O操作(Synchronous I/O operation)
导致请求进程阻塞,直到I/O操作完成
-
异步I/O操作(Asynchronous I/O operation)
不导致请求进程阻塞
-
阻塞( Blocking )
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
-
非阻塞( Nonblocking)
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
同步异步,阻塞非阻塞是分别2个不同的概念,它们之间不是相互对应的,但是有关联。
I/O模型
在UNIX
中存在的5种I/O模型:
阻塞式I/O
, 非阻塞式I/O
, I/O复用[select,poll]
,信号驱动式I/O
, 异步I/O (POSIX的aio函数)
-
阻塞式I/O
-
非阻塞式I/O
-
I/O复用[select,poll]
-
信号驱动式I/O
-
异步I/O (POSIX的aio函数)
一个简单的输入操作通常包括两个不同阶段:
- 等待数据准备好;
- 从内核向进程复制数据。
阻塞式I/O模型
默认情况下,所有socket都是阻塞的。
recvfrom系统调用,从进程转入kernel,直到kernel的数据准备好,再将数据从kernel拷到用户内存,kernel返回结果,进程解除阻塞。就是说从recvfrom直到返回的时间内进程是被阻塞的
。
非阻塞式I/O
进程把socket设置为非阻塞,这样当有I/O请求操作的时候,不会把进程阻塞,而是返回一个错误。
recvfrom在前3次调用没有数据返回,kernel立即返回一个EWOULDBLOCK
错误,第4次有数据准备好,就被copy到进程的缓冲区,然后返回结果。
在非阻塞的recvfrom调用之后,进程没有被阻塞,kernel返回错误,进程在接到返回后会去做其他的事情,然后间隔一段时间后再次发起recvfrom调用,重复直到完成。这个过程被称为轮询
。但是轮询这种操作耗费大量的CPU时间,推高CPU的占用率
I/O复用
I/O复用(IO multiplexing),可以调用select
或者poll
,阻塞在这2个系统调用的某个上,而不是阻塞在真正的I/O系统调用上
用户进程调用select
,那么进程会被阻塞,kernel监视所有select
的socket
,当任一个socket
数据准备好后,select
返回可读标识,用户进程调用read
,将数据从kernel拷贝到用户进程。
I/O复用中的2个系统调用(select,read),它的好处在于通过select来处理多个connection
,它对于每个socket
,都是非阻塞。
信号驱动式I/O
skip
异步I/O
调用aio_read函数,给kernel传递参数,告诉kernel当整个操作完成后如何通知。该系统调用立刻返回,而且在等待I/O完成期间,进程不被阻塞。
模型比较
前4中模型区别在第一阶段,第二阶段是一样的(在data从内核复制到调用者的缓冲区期间,进程阻塞在recvfrom)。而异步I/O在这2个阶段都处理。
所以前4种都属于同步I/O,因为真正的I/O操作(recvfrom)将阻塞进程。只有异步I/O与POSIX定义的异步I/O匹配。