I/O操作

Posted 四季帆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了I/O操作相关的知识,希望对你有一定的参考价值。

前言

I/O操作即操作存储器,所以想了解I/O操作,需要了解一点存储器相关知识点。

计算机存储器

存储器是计算机的核心部件之一,在完全理想的状态下,存储器应该要同时具备以下三种特性:

(1)速度足够快:存储器的存取速度应当快于 CPU 执行一条指令,这样 CPU 的效率才不会受限于存储器。
(2)容量足够大:容量能够存储计算机所需的全部数据。
(3)价格足够便宜:价格低廉,所有类型的计算机都能配备。

但是现实往往是残酷的,我们目前的计算机技术无法同时满足上述的三个条件,于是现代计算机的存储器设计采用了一种分层次的结构:

从顶至底,现代计算机里的存储器类型分别有:寄存器、高速缓存、主存和磁盘,这些存储器的速度逐级递减而容量逐级递增。存取速度最快的是寄存器,因为寄存器的制作材料和 CPU 是相同的,所以速度和 CPU 一样快,CPU 访问寄存器是没有时延的,然而因为价格昂贵,因此容量也极小,一般 32 位的 CPU 配备的寄存器容量是 32x32 Bit,64 位的 CPU 则是 64x64 Bit,不管是 32 位还是 64 位,寄存器容量都小于 1 KB,且寄存器也必须通过软件自行管理。

第二层是高速缓存,也即我们平时了解的 CPU 高速缓存 L1、L2、L3,一般 L1 是每个 CPU 独享,L3 是全部 CPU 共享,而 L2 则根据不同的架构设计会被设计成独享或者共享两种模式之一,比如 Intel 的多核芯片采用的是共享 L2 模式而 AMD 的多核芯片则采用的是独享 L2 模式。

第三层则是主存,也即主内存,通常称作随机访问存储器(Random Access Memory, RAM)。是与 CPU 直接交换数据的内部存储器。它可以随时读写(刷新时除外),而且速度很快,通常作为操作系统或其他正在运行中的程序的临时资料存储介质。

最后则是磁盘,磁盘和主存相比,每个二进制位的成本低了两个数量级,因此容量比之会大得多,动辄上 GB、TB,而问题是访问速度则比主存慢了大概三个数量级。机械硬盘速度慢主要是因为机械臂需要不断在金属盘片之间移动,等待磁盘扇区旋转至磁头之下,然后才能进行读写操作,因此效率很低。

Linux内部层级

read/write和mmap的区别

Linux的I/O操作是设置了缓冲区机制的,设置缓冲区最大的好处是可以减少磁盘 I/O 的操作,如果所请求的数据已经存放在操作系统的缓冲区中,那么就不需要再进行实际的物理磁盘 I/O 操作。

常规的文件操作为了提高读写效率和保护磁盘,使用了页缓存机制。这样造成读文件时需要先将文件页从磁盘拷贝到页缓存中,由于页缓存处在内核空间,不能被用户进程直接寻址,所以还需要将页缓存中数据页再次拷贝到内存对应的用户空间中。这样,通过了两次数据拷贝过程,才能完成进程对文件内容的获取任务。写操作也是一样,待写入的 Buffer 在内核空间不能直接访问,必须要先拷贝至内核空间对应的主存,再写回磁盘中(延迟写回),也是需要两次数据拷贝。

文件越大 read/write 就耗时越长,所以对于一些大文件 mmap 效率更高。

综上,read/write 操作需要经历磁盘文件到内核页缓存再到用户空间缓存的两次数据拷贝。而 mmap 函数只需要从磁盘文件拷贝到内核缓存,经过一次拷贝即可,然后用户进程直接就可以通过 Share 的方式进行访问。

系统api和库函数的区别(以write为例)

系统API是内核态下的缓冲区,区分于C库函数中的write,C库函数中的write自己也实现了一个缓冲区。

C库提供的write接口也是在系统API的基础上封装的,所以调用C库提供的write接口会多出一个缓冲区的开销,但是C库提供的接口功能更多。

以上是关于I/O操作的主要内容,如果未能解决你的问题,请参考以下文章

boost::asio 错误“I/O 操作已中止...”

java基础之I/O操作

Linux Kernel文件系统写I/O流程代码分析

什么是Redis I/O 多路复用?

springboot 底层点的知识

springboot 底层点的知识