同步非阻塞 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 并不产生效果。