注:上一章:服务器IO底层原理
IO一共分为四种模型:
1.同步阻塞IO
2.同步非阻塞IO
3.IO多路复用模型
4.异步IO模型
在阅读本章之前,需要了解的概念
1.阻塞:指需要内核IO操作彻底完成后,才返回到用户空间执行用户操作,传统的IO和socket默认创建的IO都为阻塞IO
2.非阻塞:用户空间与内核通讯,双方会立刻返回对方一个状态值,拿到状态值后就知道现在可不可以操作,java中socket设置为NONBLOCK表示非阻塞
3.同步:指用户空间的线程主动发起IO请求的一方,内核是被动接受者。
4.异步:系统内核IO是主动发起IO请求的一方,用户空间的线程是接受者,用户需要先向内核空间注册IO事件的回调函数,由内核主动调用
同步阻塞IO
名为Asynchronous IO,java中socket创建的默认都是同步阻塞IO
优点:该模式简单(用户线程阻塞期间挂起,不会占用CPU资源)
缺点:每个连接配独立线程,高并发下需要大量线程维护网络连接,内存和线程切换开销大
具体操作流程:
1.java启动IO的read方法
2.内核收到read系统调用,开始准备接受数据(一开始可能还没数据到达内核缓冲区,内核和用户都处于等待状态,其中内核和内核缓冲区两个概念)
3.内核缓冲区到了有数据来了,开始接受数据,用户处于等待状态
4.内核缓冲区收到数据完整后,将数据复制到进程缓冲区
5.复制完成后,内核返回用户结果(如复制了多少字节之类的结果)
6.用户收到结果后,解除阻塞状态
同步非阻塞IO
名为None Blocking IO(NIO),其并非java中说的NIO,在socket连接中需要设置非阻塞模式
优点:用户线程不会阻塞,实时性好
缺点:用户线程需要不断轮询内核,占CPU时间,效率低
具体操作流程:
1.java启动IO的read方法
2.内核缓冲区收到后在没有接收到完整数据时立即返回状态值
3.用户不断发起IO系统调用,内核也不断返回状态值
4.内核缓冲区数据接收完成后,最近遇到用户发起的IO时,用户开始阻塞,内核缓冲区开始复制数据
5.复制完成后,内核返回用户结果(如复制了多少字节之类的结果)
6.用户收到结果后,解除阻塞状态
IO多路复用模型
该模型指java里说的NIO(记java NIO),引入新的系统支持的系统调用模式,优化了同步非阻塞IO轮询。通过该系统调用可以达到一个进程轮询监控多个文件,当其中某个或某些到达就绪状态时会返回对应可执行读写操作。目前该系统调用有select(基本上所有操作系统都支持)。
优点:相对于同步非阻塞IO,可以一个选择器查询成千上万个连接,系统不必创建和维护大量线程
缺点:数据从内核缓冲区复制到用户缓冲区的过程,还是阻塞的
具体操作流程:
1.选择注册器(将需要read的目标提前注册到select选择器中,在java选择器中对应的是Selector类)
2.就绪轮询(通过选择器查询方法,查询注册过所有的连接。当任意一个注册过的数据准备好了,内核就将该socket加入就绪列表返回给调用端,其中用户调用select查询方法时,整个查询线程会被阻塞掉)
3.用户获取就绪状态后根据返回值发起read系统调用,用户线程阻塞内核缓冲区复制数据
5.复制完成后,内核返回用户结果(如复制了多少字节之类的结果)
6.用户收到结果后,解除阻塞状态
异步IO模型
名为Asynchronous IO(记AIO),用户通过系统调用,往内核里注册某个IO操作,内核在整个IO操作(包括准备数据和复制数据到用户进程)完成后通知用户程序。
优点:数据从内核缓冲区复制到用户缓冲区的过程 和内核等待过程,用户都不是阻塞的
缺点:需要内核提供支持。可悲的是目前Linux尚不完善,其底层仍使用epoll实现,与java NIO相比没啥优势。(window系统下通过IOCP实现了真正的异步IO)
具体操作流程:
1.用户发起read系统调用,非阻塞去做其他事
2.内核缓冲区收到数据后会自动复制到用户进程
3.内核会给用户线程发一个信号或者回调用户线程注册的回调接口
4.用户线程读取用户缓冲区数据
本章是作者看书后自己的见解,如有错误欢迎大家来纠正