阻塞非阻塞与同步异步

五种IO模型详解

5种IO模型分别是阻塞IO模型、非阻塞IO模型、IO复用模型、信号驱动的IO模型、异步IO模型

1. 什么是IO

IO (Input/Output,输入/输出)即数据的读取(接收)或写入(发送)操作,通常用户进程中的一个完整IO分为两阶段:用户进程空间<–>内核空间、内核空间<–>设备空间(磁盘、网络等)。IO有内存IO、网络IO和磁盘IO三种,通常我们说的IO指的是后两者。网络I/O就是通过网络进行数据的拉取和输出。磁盘I/O主要是对磁盘进行读写工作。
在这里插入图片描述
LINUX中进程无法直接操作I/O设备,其必须通过系统调用请求kernel来协助完成I/O动作;内核会为每个I/O设备维护一个缓冲区。

对于一个输入操作来说,进程IO系统调用后,内核会先看缓冲区中有没有相应的缓存数据,没有的话再到设备中读取,因为设备IO一般速度较慢,需要等待;内核缓冲区有数据则直接复制到进程空间。

所以,对于一个网络输入操作通常包括两个不同阶段:

  • 等待网络数据到达网卡→读取到内核缓冲区,数据准备好;
  • 从内核缓冲区复制数据到进程空间

2. 什么是用户空间和内核空间

虚拟内存被操作系统划分成两块:内核空间和用户空间。
为了安全,它们是隔离的,即使用户的程序崩溃了,内核也不受影响。

内核空间是内核代码运行的地方,
用户空间是用户程序代码运行的地方。

当进程运行在内核空间时就处于内核态,当进程运行在用户空间时就处于用户态

3.同步与异步?

首先同步和异步是对于被调用方来说的,比如说你陪你女朋友去逛商场这个方法,然后看到某家美甲店,她要进去作美甲,这时候你女朋友有两个选择

1.做完美甲在美甲店等你来接她。

2.做完美甲打电话给你让你来接她。

这期间你自己可以选择是在店里等他还是选择去哪里先逛,你女朋友就不管你了,爱干啥干啥去。对于她自己来说,她选择做做完美甲在店里等你,那就是一个同步操作,她的时间和状态停留在了做美甲的前一刻,接下来要和你同步继续逛商场。

选择做完打电话给你就是一个异步操作。

4.阻塞与非阻塞?

还是上面那个例子,阻塞与非阻塞是对于调用方来说的,也就是你自己的选择。女朋友要做美甲,你也有连个选择

1.在店里等他

2.闲得无聊就先去商场晃晃呗。

你在店里等他就是阻塞住了,啥事也干不了,就等她做美甲了,如果先去商场逛,那就美滋滋了,那就是非阻塞的了。

基于同步,异步,阻塞和非阻塞,还有标准IO的两阶段读取,IO发展出了这么几种模型。

– 阻塞 I/O(blocking IO)
  – 非阻塞 I/O(nonblocking IO)
  – I/O 多路复用( IO multiplexing)
  – 信号驱动 I/O( signal driven IO)
  – 异步 I/O(asynchronous IO)

5. 五种IO模型详解

5.1 阻塞IO模型

当用户线程发出IO请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除block状态。
在这里插入图片描述
阻塞非阻塞与同步异步_第1张图片

进程发起IO系统调用后,进程被阻塞,转到内核空间处理,整个IO处理完毕后返回进程。操作成功则进程获取到数据

5.2 非阻塞IO模型

进程发起IO系统调用后,如果内核缓冲区没有数据,需要到IO设备中读取,进程返回一个错误而不会被阻塞;进程发起IO系统调用后,如果内核缓冲区有数据,内核就会把数据返回给进程。

对于上面的阻塞IO模型来说,内核数据没准备好需要进程阻塞的时候,就返回一个错误,以使得进程不被阻塞。

在这里插入图片描述
阻塞非阻塞与同步异步_第2张图片

在非阻塞IO模型中,用户线程需要不断地询问内核数据是否就绪,也就说非阻塞IO不会交出CPU,而会一直占用CPU。

5.3 IO复用模型

多个的进程的IO可以注册到一个复用器(select)上,然后用一个进程调用该select,,select会监听所有注册进来的IO。

如果select没有监听的IO在内核缓冲区都没有可读数据,select调用进程会被阻塞;而当任一IO在内核缓冲区中有可数据时,select调用就会返回;而后select调用进程可以自己或通知另外的进程(注册进程)来再次发起读取IO,读取内核中准备好的数据。

在这里插入图片描述
阻塞非阻塞与同步异步_第3张图片

典型应用: select、 poll、 epoll三种方案,nginx都可以选择使用这三个方案

select、poll、 epoll在Linux中IO复用 的实现方式主要有
select, poll和epoll

Select:注册IO、阻塞扫描,监听的IO最大连接数不能多于FD_ SIZE(1024);
Poll:原理和Select相似,没有数量限制,但IO数量大扫描线性性能下降;
Epoll :事件驱动不阻塞, mmap实现内核与用户空间的消息传递,数量很大,Linux2.6后内核支持

5.4 信号驱动IO模型

在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个信号函数,然后用户线程会继续执行,当内核数据就绪时会发送一个信号给用户线程,用户线程接收到信号之后,便在信号函数中调用IO读写操作来进行实际的IO请求操作。这个一般用于UDP中,对TCP套接口几乎是没用的,原因是该信号产生得过于频繁,并且该信号的出现并没有告诉我们发生了什么事情。

在这里插入图片描述
阻塞非阻塞与同步异步_第4张图片

当进程发起一个IO操作,会向内核注册一个信号处理函数,然后进程返回不阻塞;当内核数据就绪时会发送一个信号给进程,进程便在信号处理函数中调用IO读取数据

5.5 异步IO模型

当进程发起一个IO操作,进程返回(不阻塞),但也不能返回结果;内核把整个IO处理完后,会通知进程结果。如果IO操作成功则进程直接获取到数据

在这里插入图片描述
阻塞非阻塞与同步异步_第5张图片

注意:
此模型和前面模型最大的区别是:前4个都是阻塞的,因为需要自己把用户准备好的数据,放在我的用户空间,而全异步都帮我们做好了。
用户线程完全不需要关心实际的整个IO操作是如何进行的,只需要先发起一个请求,当接收内核返回的成功信号时表示IO操作已经完成,可以直接去使用数据了。它是最理想的模型。

总结

我觉得可以这样理解,阻塞与非阻塞是针对IO操作,根据IO操作是否立即返回来决定是否是阻塞操作;同步异步是针对进行IO操作的线程,线程是否立即返回来决定是否是同步异步操作。

你可能感兴趣的:(#,JAVA并发)