IO模型¶
同步与异步¶
关注的是消息通信机制。调用的对象是否立即返回。
- 同步指的是调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为。调用者主动等待调用结果。
- 异步指的是调用立刻返回,调用者不必等待方法内的代码执行结束,就可以继续后续的行为。没有返回结果。被调用者通知调用者。
阻塞与非阻塞¶
关注的是程序在等待调用结果。调用者的状态。
- 阻塞指的是遇到同步等待后,一直在原地等待同步方法处理完成。
- 非阻塞指的是遇到同步等待,不在原地等待,先去做其他的操作,隔断时间再来观察同步方法是否完成。
非阻塞IO¶
- 内核在没有准备好数据的时候会返回错误码,而调用程序不会休眠,而是不断轮询询问内核数据是否准备好
- 如果数据没有准备好,不像阻塞式IO那样一直被阻塞,而是返回一个错误码。数据准备好时,函数成功返回。
- 应用程序对这样一个非阻塞描述符循环调用成为轮询。
- 非阻塞式IO的轮询会耗费大量cpu,通常在专门提供某一功能的系统中才会使用。通过为套接字的描述符属性设置非阻塞式,可使用该功能
IO多路复用¶
- 类似与非阻塞,只不过轮询不是由用户线程去执行,而是由内核去轮询,内核监听程序监听到数据准备好后,调用内核函数复制数据到用户态
- IO多路复用至少有两次系统调用,如果只有一个代理对象,性能上是不如前面的IO模型的,但是由于它可以同时监听很多套接字,所以性能比前两者高
- select:线性扫描所有监听的文件描述符,不管他们是不是活跃的。有最大数量限制
- poll:同select,不过数据结构不同,需要分配一个pollfd结构数组,维护在内核中。它没有大小限制,不过需要很多复制操作
- epoll:用于代替poll和select,没有大小限制。使用一个文件描述符管理多个文件描述符,使用红黑树存储。同时用事件驱动代替了轮询。epoll_ctl中注册的文件描述符在事件触发的时候会通过回调机制激活该文件描述符。epoll_wait便会收到通知。最后,epoll还采用了mmap虚拟内存映射技术减少用户态和内核态数据传输的开销

零拷贝¶
上下文切换:当用户程序向内核发起系统调用时,CPU 将用户进程从用户态切换到内核态;当系统调用返回时,CPU 将用户进程从内核态切换回用户态
传统的 I/O 读取方式,read 会触发 2 次上下文切换,1 次 DMA 拷贝和 1 次 CPU 拷贝
传统的 I/O 写入方式,write会触发 2 次上下文切换,1 次 CPU 拷贝和 1 次 DMA 拷贝
实现方式¶
用户态直接I/O¶
- 用户态直接 I/O 使得应用进程或运行在用户态(user space)下的库函数直接访问硬件设备,数据直接跨过内核进行传输
- 能适用于不需要内核缓冲区处理的应用程序。CPU与磁盘操作执行时间差距大,需要配合异步。
mmap + write¶
- 一种零拷贝方式是使用 mmap + write 代替原来的 read + write 方式,减少了 1 次 CPU 拷贝操作。4 次上下文切换,1 次 CPU 拷贝和 2 次 DMA 拷贝。
- 使用 mmap 的目的是将内核中读缓冲区(read buffer)的地址与用户空间的缓冲区(user buffer)进行映射,从而实现内核缓冲区与应用程序内存的共享,省去了将数据从内核读缓冲区(read buffer)拷贝到用户缓冲区(user buffer)的过程,然而内核读缓冲区(read buffer)仍需将数据到内核写缓冲区(socket buffer)
- 不适合小文件,内存映射总是要对齐页边界。
sendfile¶
- 不仅减少了 CPU 拷贝的次数,还减少了上下文切换的次数。2次上下文切换,1 次 CPU 拷贝和 2 次 DMA 拷贝。
- 数据可以直接在内核空间内部进行 I/O 传输,从而省去了数据在用户空间和内核空间之间的来回拷贝。与 mmap 内存映射方式不同的是, sendfile 调用中 I/O 数据对用户空间是完全不可见的。
- 用户程序不能对数据进行修改
sendfile + DMA gather copy¶
- 2 次上下文切换、0 次 CPU 拷贝以及 2 次 DMA 拷贝
- 不再从内核缓冲区的数据拷贝到 socket 缓冲区,仅仅是缓冲区文件描述符和数据长度的拷贝,这样 DMA 直接利用 gather 操作将页缓存中数据打包发送到网络中
JAVA NIO中的零拷贝¶
Java NIO 中的通道(Channel)就相当于操作系统的内核空间(kernel space)的缓冲区,而缓冲区(Buffer)对应的相当于操作系统的用户空间(user space)中的用户缓冲区(user buffer)。
- MappedByteBuffer :基于内存映射(mmap)
- FileChannel :基于 sendfile

