io读写的方式
- 中断
- DMA
中断方式
中断方式的流程图如下:
1.用户进程发起数据读取请求
2.系统调度为该进程分配cpu
3.cpu向io控制器(ide,scsi)发送io请求
4.用户进程等待io完成,让出cpu
5.系统调度cpu执行其他任务
6.数据写入至io控制器的缓冲寄存器
7.缓冲寄存器满了向cpu发出中断信号
8.cpu读取数据至内存
缺点:中断次数取决于缓冲寄存器的大小
DMA : 直接内存存取
DMA方式的流程图如下:
1.用户进程发起数据读取请求
2.系统调度为该进程分配cpu
3.cpu向DMA发送io请求
4.用户进程等待io完成,让出cpu
5.系统调度cpu执行其他任务
6.数据写入至io控制器的缓冲寄存器
7.DMA不断获取缓冲寄存器中的数据(需要cpu时钟)
8.传输至内存(需要cpu时钟)
9.所需的全部数据获取完毕后向cpu发出中断信号
优点:减少cpu中断次数,不用cpu拷贝数据
数据拷贝
下面展示了 传统方式读取数据后并通过网络发送 所发生的数据拷贝:
1.一个read系统调用后,DMA执行了一次数据拷贝,从磁盘到内核空间
2.read结束后,发生第二次数据拷贝,由cpu将数据从内核空间拷贝至用户空间
3.send系统调用,cpu发生第三次数据拷贝,由cpu将数据从用户空间拷贝至内核空间(socket缓冲区)
4.send系统调用结束后,DMA执行第四次数据拷贝,将数据从内核拷贝至协议引擎
另外,这四个过程中,每个过程都发生一次上下文切换
- 内存缓冲数据,主要是为了提高性能,内核可以预读部分数据,当所需数据小于内存缓冲区大小时,将极大的提高性能。
- 零拷贝是为了消除这个过程中冗余的拷贝
零拷贝-sendfile
对应到java中
为FileChannel.transferTo(long position, long count, WritableByteChannel target)
//将数据从文件通道传输到了给定的可写字节通道
避免了第2,3步的数据拷贝,参考下图:
1.DMA从拷贝至内核缓冲区
2.cpu将数据从内核缓冲区拷贝至内核空间(socket缓冲区)
3.DMA将数据从内核拷贝至协议引擎
4.这三个过程中共发生2次上下文切换,分别为发起读取文件和发送数据
以上过程发生了三次数据拷贝,其中有一次为cpu完成
linux内核2.4以后,socket缓冲区做了调整,DMA带收集功能,如下图:
1.DMA从拷贝至内核缓冲区
2.将数据的位置和长度的信息的描述符增加至内核空间(socket缓冲区)
3.DMA将数据从内核拷贝至协议引擎
零拷贝-mmap
对应到java中为MappedByteBuffer//文件内存映射
数据不会复制到用户空间,只在内核空间,与sendfile类似,但是应用程序可以直接操作该内存。