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