Java NIO:浅析I/O模型:https://www.cnblogs.com/dolphin0520/p/3916526.html
同步/异步 + 阻塞/非阻塞
- 同步阻塞:
- 同步非阻塞:
- 异步阻塞:
- 异步非阻塞:
《Unix 网络编程》:阻塞 IO、非阻塞 IO、多路复用 IO、信号驱动 IO、异步 IO
IO 操作的两个阶段:
- 询问是否就绪、复制从内核空间数据
同步与异步:
同步:如果有多个任务或者事件要发生,这些任务或者事件必须逐个地进行,一个事件或者任务的执行会导致整个流程的暂时等待,这些事件没有办法并发地执行;
异步:如果有多个任务或者事件发生,这些事件可以并发地执行,一个事件或者任务的执行不会导致整个流程的暂时等待。
异步只是宏观上地一个模式,多线程 ≠ 异步,多线程只是实现异步的一种手段,多进程和多协程也可以实现异步。
阻塞与非阻塞:
阻塞:当某个事件或者任务在执行过程中,它发出一个请求操作,但是由于该请求操作需要的条件不满足,那么就会一直在那等待,直至条件满足;
非阻塞:当某个事件或者任务在执行过程中,它发出一个请求操作,如果该请求操作需要的条件不满足,会立即返回一个标志信息告知条件不满足,不会一直在那等待。
同步和异步 ≠ 阻塞和非阻塞:
同步和异步着重点在于多个任务的执行过程中,一个任务的执行是否会导致整个流程的暂时等待;
阻塞和非阻塞着重点在于发出一个请求操作时,如果进行操作的条件不满足是否会返会一个标志信息告知条件不满足。
同步非阻塞:
即 NIO,多路复用 IO
用一个线程处理多件事,这些事必须一步一步地完成,即同步。
- 比如先注册 Channel 和 key 到 selector,然后再后续完成对发生的 key 的处理
非阻塞:操作 IO 的时候,不需要等待它完成,而是会马上返回。后续有结果后,用户线程再去取出来
同步 IO 与异步 IO:
《Unix 网络编程》:
A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes. An asynchronous I/O operation does not cause the requesting process to be blocked.
同步 IO:如果一个线程请求进行 IO 操作,在 IO 操作完成之前,该线程会被阻塞; 异步 IO:如果一个线程请求进行 IO 操作,IO 操作不会导致请求线程被阻塞。
用户线程与内核的交互:
- 同步 IO:用户线程发出 IO 请求操作之后,如果数据没有就绪,需要通过用户线程或者内核不断地去轮询数据是否就绪,当数据就绪时,再将数据从内核拷贝到用户线程
- 异步 IO:只有 IO 请求操作的发出是由用户线程来进行的,IO 操作的两个阶段都是由内核自动完成,然后发送通知告知用户线程 IO 操作已经完成
也就是说在异步 IO 中,不会对用户线程产生任何阻塞。
同步 IO 和异步 IO 的关键区别反映在数据拷贝阶段是由用户线程完成还是内核完成。所以说异步 IO 必须要有操作系统的底层支持。
阻塞 IO 和非阻塞 IO 是反映在当用户请求 IO 操作时,如果数据没有就绪,是用户线程一直等待数据就绪,还是会收到一个标志信息这一点上面的。也就是说,阻塞 IO 和非阻塞 IO 是反映在 IO 操作的第一个阶段,在查看数据是否就绪时是如何处理的。
《Unix 网络编程》:阻塞 IO、非阻塞 IO、多路复用 IO、信号驱动 IO、异步 IO
Unix IO:
阻塞 IO 模型:
当用户线程发出 IO 请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出 CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除 block 状态。
data = socket.read()
非阻塞 IO 模型:
当用户线程发起一个 read 操作后,并不需要等待,而是马上就得到了一个结果。如果结果是一个 error 时,它就知道数据还没有准备好,于是它可以再次发送 read 操作。一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回。
在非阻 塞IO 模型中,用户线程需要不断地询问内核数据是否就绪,也就说非阻塞 IO 不会交出 CPU
while (true) {
data = socket.read();
if (data != error) {
处理数据;
break;
}
}