• Java IO 学习(三)缓冲IO / 直接IO / 内存映射


    缓冲IO

    在介绍缓冲IO之前需要先了解一下常用的机械硬盘的原理与特点

    一个机械硬盘中装有多个盘片

    每个盘片上有多个同心圆(磁道)

    每个同心圆又由多个弧(扇区)组成,每个弧上都记录了等量的数据(比方说512byte)

    如果发起一个随机读写请求,磁头需要先找到对应的磁道,然后等待对应的扇区旋转到磁头正下方才能开始读取数据(民用机械硬盘的转速一般在5400或者7200RPM,工业界倒是经常使用10000RPM的机械硬盘。但是它们的寻道时间大概都在几ms到十几ms左右)

    机械硬盘的顺序读写很快(一般在100-200MB/s),但是随机读写很慢(寻道时间在十几ms,导致随机读写的iops只有几十)

    假定我们不做任何额外的优化处理,在用户发起读数据请求的时候,直接调用硬盘驱动读取磁盘数据并返回

    设想一个场景:循环调用read方法读取文件,但是每次只读取较少的数据(比方说每次只读一个byte)。那么每次read请求都对应于一次对磁盘的随机读写(两次读请求之前需要重新寻道),也就是说read操作的tps只有几十。

    也就是说此时磁盘占用率为100%,但是只能提供不到100byte/s的数据读取率,这显然是不可接受的。

    Linux对此有个很简单的优化,就是在内核中维护一块缓冲区(buffer cache),在用户第一次调用read读取数据的时候,无论用户想要读取的数据有多小,都会一次性从磁盘中加载一段数据放到缓冲区中,这样用户下一次调用read方法的时候可以直接从缓冲区中返回数据,不用再次访问磁盘了。

    write方法也是同理,用户写入的数据不是直接落盘,而是先写到kernel中的缓冲区里,按照一定的策略批量刷盘。当然也可以调用flush方法强制将缓存区的数据落盘。

    这个优化极大的提高了顺序读写的效率。由于直接读写的是kernel中的缓冲区而不是磁盘,这种IO被称为缓冲IO。

    直接IO

    一般来说,上面介绍的缓冲IO已经足够应付日常需求了。但是像数据库这种极度依赖IO的应用程序,为了追求极致的性能,往往更加愿意自己直接操作磁盘。

    直接IO可以直接将数据从磁盘复制到用户空间,或者将数据从用户空间写到磁盘,减少了kernel中的缓冲区这一环节,这是直接IO可以提高性能的原理。

    但是如果用得不好就悲剧了,所以直接IO只在少数场景下使用。

    内存映射

    先给出mmap的官方文档

    mmap方法会返回一个void *类型的指针ptr,它指向进程逻辑空间中的一个地址。

    后续如果想要读写文件,无需调用read/write方法, 而是直接操作这个ptr指针即可。

    用户试图向ptr指针指向的空间读写数据时,由于MMU无法在物理内存中找到对应的地址,会触发一次缺页中断,OS会去硬盘中找到对应的数据并复制到内存中,然后用户就能正常完成读写操作了。这个过程是由操作系统自动完成的。

    为什么说内存映射效率比缓冲IO要高?

    我们回忆一下缓冲IO的工作流程:

    1. 用户调用read方法

    2. 调用系统调用,触发中断,进程从用户态进入内核态

    3. 从硬盘中读取数据并复制到kernel缓冲区

    4. 将数据从kernel缓存区复制到用户提供的byte数组中

    5. 进程从内核态返回到用户态

    完成

    从上面的流程中我们可以看到,调用一次read方法,最多可能会引起两次用户态与内核态之间的切换,以及两次数据复制

    而内存映射呢?

    1. 用户试图访问ptr指向的数据

    2. MMU解析失败,触发缺页中断,程序从用户态进入到内核态

    3. 从硬盘中读取数据并复制到进程空间中ptr指向的逻辑空间里

    4. 进程从内核态返回到用户态

    完成

    可以看出,试图访问内存映射文件,最多可能会引起两次用户态与内核态之间的切换,以及一次数据复制

    也就是说,内存映射与缓冲IO相比,可以节省数据复制带来的开销,因此效率较高。

    参考资料

    Linux 中直接 I/O 机制的介绍

    内存映射文件原理探索

  • 相关阅读:
    【兼容性】IE不支持日期字符串转换为日期对象
    tinydate.js[v0.2] 优化了调用方式
    tinydate.js[v0.1]关于Javascript Date的工具
    【兼容性】IE10不支持参数默认值即可选参数
    【兼容性】IE10不支持lamda表达式
    创建第一个core项目(netCore学习笔记1)
    .net(C#)在Access数据库中执行sql脚本
    (Lesson2)根据类名称和属性获得元素-JavaScript面向对象
    UWP Tiles
    UWP Ad
  • 原文地址:https://www.cnblogs.com/stevenczp/p/7496089.html
Copyright © 2020-2023  润新知