Different I/O

要了解I/O之前,需要先了解用户态与内核态的概念,可以看《Kernel mode 与 User mode》

1、一次网络通信的简单过程描述

(1)数据接收好到达kernel buffer(wait阶段)
(2)数据从kernel buffer拷贝到user buffer(copy阶段)

2、各种I/O方式分析

(1)blocking I/O


blocking I/O

当用户调用recvfrom时,kernel就开始准备数据。当数据还没有完全到达时,对于用户来说,整个线程就会被阻塞。当kernel等到数据完全准备好,就开始将数据从内核拷贝到进程中,完了以后内核才返回信息,用户线程才能解除block。所以对于用户来说,准备数据与拷贝数据两个过程都是阻塞的。当请求的连接比较多时,则需要开多个线程来处理,存在很大弊端。
(2)no-blocking I/O(非阻塞I/O)


no-blocking I/O

使用no-blocking I/O的话,当数据已经就绪,则返回数据,否则就立刻返回一个错误,处于非block状态。程序可以间隔时间地来请求以得知数据是否已经加载完全。当准备数据完毕,进入拷贝数据阶段,则这个时候线程进入阻塞状态。所以对于no-blocking I/O来说,准备数据是不阻塞的,拷贝数据是阻塞的。
(3)I/O multiplexing(I/O多路复用)
I/O multiplexing

I/O multiplexing的原理是使用系统提供的select/epoll等这些函数去不断轮训所负责的socket,而不是让用户线程自己去轮训。当用户线程调用select时,整个线程会被block,同时,kernel会监视select所负责的所有socket,当有一个数据已经准备就绪,select就会返回,这时用户线程再调用read操作,将数据从kerne拷贝到用户进程中。
I/O multiplexing在调用上会多调用一次系统级别调用(read请求)。所以当连接数不是很高的情况下,使用select/epoll不会比multi-thread+blocking I/O(开多个线程,各自阻塞等待数据到来)性能好,可能延迟还更大,但是优点在于能够用较少资源处理更多的连接,即一个线程能够监听多个socket的状态,比如传入多个socket,如果有一个socket就绪,则返回,否则阻塞直到超时。所以,在高并发的场景中,比如要处理10000个连接,只需要1个线程监控就绪状态,对就绪的每个连接开一个线程处理或者直接丢到线程池处理,当然也可以用当前线程处理。即这个I/O线程可以同时管理多个连接,也就是多路复用了。
Java 中的NIO就是基于I/O multiplexing实现。

(4)asynchronous io


asynchronous io

用户发起read操作时,系统立即返回。对于kernel而言,则进行准备数据与拷贝数据两个动作,当这两个动作完成以后,则发送signal给用户线程,线程可以去获取数据。全程没有发生block。

3、各种io的对比

(1)blocking I/O与 no-blocking I/O
blocking I/O:在wait与copy阶段都会阻塞进程。
no-blocking I/O:在wait阶段不会阻塞,在copy阶段会阻塞。
(2)synchronous io与 asynchronous io
synchronous I/O:I/O过程中线程会被阻塞,直到I/O完成
asynchronous I/O:I/O过程中线程不会被阻塞,操作系统完成I/O操作以后通知到系统线程
(3)blocking I/O、no-blocking I/O、I/O multiplexing都属于synchronous io

你可能感兴趣的:(Different I/O)