I/O 模型 03 - 同步非阻塞 I/O

同步非阻塞 I/O

在同步阻塞 I/O 中,进程实际上等待的时间可能包括两部分,一个是等待数据的就绪,另一个是等待数据的复制, 对于网络 I/O 来说,前者的时间可能要更长一些。

与此不同的是,同步非阻塞 I/O 的调用不会等待数据的就绪,如果数据不可读或者不可写,它会立即告诉进程。 比如我们使用非阻塞 recv() 接收网络数据的时候,如果网卡缓冲区中没有可接收的数据,函数就及时返回,告诉进程没有数据可读了。 相比于阻塞 I/O,这种非阻塞 I/O 结合反复轮询来尝试数据是否就绪,防止进程被阻塞, 最大的好处便在于可以在一个进程里同时处理多个 I/O 操作。

但正是由于需要进程执行多次轮询来查看数据是否就绪,这花费了大量的 CPU 时间,使得进程处于忙碌等待的状态。

回到买面条的故事中,假如你不甘心等着面条做好,想去顺便逛逛街,可又担心面条做好后没有及时领取, 所以你逛一会儿便跑回去看看面条是否做好,往返了很多次,最后虽然及时地吃上了面条,但是却累得气喘吁吁。

非阻塞 I/O 一般只针对网络 I/O 有效,我们只要在 socket 的选项设置中使用 O_NONBLOCK 即可, 这样对于该 socket 的 send() 或 recv() 便采用非阻塞方式。值得注意的是,对于磁盘 I/O, 非阻塞 I/O 并不产生效果。

Ref

摘自《构建高性能 Web 站点》第 3 章 服务器并发处理能力 3.6 I/O 模型