1) 同步阻塞IO(Blocking IO)
2) 同步非阻塞IO(Non-blocking IO)
3) IO多路复用(IO Multiplexing)
4) 异步IO(Asynchronous IO)
(https://www.cnblogs.com/myJavaEE/p/6721127.html)
1.同步/异步
同步和异步是相对的
同步 前后两件任务, 有严格的顺序一致性(依赖和递进), 按顺序执行, 执行完一个再执行下一个, 需要等待、协调运行
异步 对顺序的要求和依赖关系没那么强, 表现出来就是两个任务可以分给两个人做, 在等待任务A结束时(同步点前)可以进行任务B
多线程就是实现异步的一个方式, 它把"第二件任务"交给其他的线程去做了. 硬件的DMA也是异步.
在实际编程中, 同步和异步区分了请求与响应的交互中, 获取响应的方式
同步: 请求某种结果, 响应返回所需结果
异步: 请求'给我结果', 第一次响应回答'我知道了', 第二次响应通知请求线程'已完成' (通过状态通知或调用请求者注册的回调函数等方式)
2.阻塞/非阻塞
阻塞和非阻塞也是相对概念
阻塞 : 请求-响应比较耗时, 如IO操作
非阻塞: 请求-响应比较迅速, 如没有等待IO完成就直接返回状态值
socket的非阻塞IO需要设置为NONBLOCK
下列内容节选自 http://www.cnblogs.com/fanzhidongyzby/p/4098546.html, 感谢原作者!
1.同步阻塞IO
最简单的IO模型,用户线程在读写时被阻塞
数据拷贝指请求到的数据先存放在内核空间, 然后从内核空间拷贝至程序的缓冲区
{ // read阻塞 read(socket, buffer); // 处理buffer process(buffer); }
用户线程在IO过程中被阻塞,不能做任何事情,对CPU的资源利用率不高
2. 同步非阻塞
用户线程不断发起IO请求. 数据未到达时系统返回一状态值; 数据到达后才真正读取数据
伪代码如下
{ // read非阻塞 while(read(socket, buffer) != SUCCESS); process(buffer); }
用户线程每次请求IO都可以立即返回,但是为了拿到数据,需不断轮询,无谓地消耗了大量的CPU
一般很少直接使用这种模型,而是在其他IO模型中使用非阻塞IO这一特性
3. IO多路复用
IO多路复用建立在内核提供的阻塞函数select上
用户先将需要进行IO操作的socket添加到select中,然后等待阻塞函数select返回。当数据到达后,socket被激活,select返回,用户线程就能接着发起read请求
伪代码如下:
{ // 注册 select(socket); // 轮询 while(true) { // 阻塞 sockets = select(); // 数据到达, 解除阻塞 for(socket in sockets) { if(can_read(socket)) { // 数据已到达, 那么socket阻不阻塞无所谓 read(socket, buffer); process(buffer); } } } }