V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
killer8998
V2EX  ›  问与答

IO 操作密集型程序怎么优化

  •  
  •   killer8998 · 2022-07-28 16:52:02 +08:00 · 948 次点击
    这是一个创建于 879 天前的主题,其中的信息可能已经有所发展或是发生改变。

    各位大佬好,我最近接手了一个 native 程序的维护工作(之前以做 Android app 为主),现在遇到一个优化问题,想看看各位有没有什么好的思路。

    简单介绍一下这个程序:1.本身是一个单线程程序,定期从一个设备中读取平台下发过来的指令 2.根据指令去操作两类文件,一类是以 ID 命名的文件,一类是汇总了 ID 信息的 bin 文件,举例:有 1-10 个 ID 文件,每个 ID 文件里保存了该文件信息在 bin 文件中的起始位置和长度,而 bin 文件包含了所有 ID 文件的信息。操作主要是新增和删除,新增是创建一个新 ID 文件,然后把相关信息附加到 bin 文件中,删除比较麻烦,需要将 bin 文件读到内存中,然后根据要删除的 ID 文件中的起始位置,做一个 memmove 操作,然后保存到 bin 文件,同时需要修改剩下全部的 ID 文件的起始位置。3.每次新增或者删除了 ID 文件后,都会通知另一个程序来读取剩下的 ID 文件和 bin 文件(可能造成 bin 文件被锁定)

    问题:如果平台指令以较慢的速度过来,程序慢慢处理的话 基本上没什么问题,但是如果平台在短时间发送大量指令下来(比如以 20ms 的间隔发送 100 条指令),程序会处于频繁的文件 IO 操作中,然后某些时候 bin 文件读取会有问题,导致后续 memmove 失败,程序崩溃

    目前的修改思路:1.平台的指令收到后先放入一个队列,由另一个线程循环读取处理,每次处理有一定的间隔 2.对 bin 文件的操作放在内存中进行,一段时间后没有新指令再写入文件(比如 10s ),同时通知另一个程序来读取变更后的文件。

    各位有更好的优化思路的话,欢迎不吝指教,谢谢

    4 条回复    2022-07-29 00:08:40 +08:00
    Mithril
        1
    Mithril  
       2022-07-28 17:04:41 +08:00
    1. 换 SSD
    2. 用内存文件映射操作你那个 bin 文件
    3. 用数据库,SQLite 也行,收到 ID 文件内容直接存到数据库里,然后隔段时间从数据库拉数据重新生成 bin

    主要问题是,不管是你用队列缓冲指令,还是隔段时间再写入 bin ,长时间把数据保存在内存里风险都会比较大。如果你需要一个可靠的方案保证数据不丢,最好就是每次变更都写入文件。
    实际上数据库就是这么干的,所以你可以用它来省点事。
    killer8998
        2
    killer8998  
    OP
       2022-07-28 17:08:57 +08:00
    @Mithril 老程序。。涉及到和另一个程序的交互。所以不能改文件的组织方式。也就是必须保持现在的 ID 文件和 BIN 文件的方式。。。感觉这种组织方式是不是本身就存在很大的隐患。。
    gfreezy
        3
    gfreezy  
       2022-07-28 17:56:47 +08:00
    这就是 bitcask 的简易实现。如果使用场景只有根据 ID 获取对应的信息,那删除 ID 的时候可以不实际删除 bin 中的数据,只删除 ID 文件,并把被删除的 ID 记录下来。定期根据被删除的 ID 对应的信息,批量清除 bin 文件数据。这样可以把每次删除一个 ID memmove 一次,合并成删除 n 多次 ID memmove 一次。应该会快不少。
    Mithril
        4
    Mithril  
       2022-07-29 00:08:40 +08:00
    @killer8998 没有改啊。
    你接受的还是 ID 文件,生成的也还是 bin 。只不过你用一个标准数据库做缓冲,来解决自己实现队列的时候可能会出的各种问题了。
    如果你每个 ID 文件的内容,在 BIN 文件中不会重叠在一起,那对于经常会新增和删除的操作来说,链表就是最佳实践了。
    你可以看看文件系统是怎么实现的,功能上是类似的。也可以用数据库去实现类似的逻辑,如果想要更安全的话。
    用链表来缓存结果,最终隔段时间刷一遍链表生成最终的 BIN 文件就行了。

    实际上如果你 ID 文件不是很多,也用不着链表。你就只把所有 ID 文件和内容存下来,然后隔段时间全读取一遍,重新计算生成 BIN 文件就行了。用数据库也只是省得你为了防止脏读自己加锁而已。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1393 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 23:57 · PVG 07:57 · LAX 15:57 · JFK 18:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.