读取图像序列的最快方法是什么?

rod*_*gob 5 c++ io performance image

我有一个速度关键的程序,它将反复从磁盘读取图像并从中计算值。图像太多,无法存储在内存中。

将读取同一组图像,我们不会更改/编辑它们,并且它们的顺序是固定的。

并非所有图像都具有相同的大小,但当编码为 PNG 时,它们都大约为 1 Mb。它们有数以万计,大部分 RAM 已经用于存储计算值。

除了购买更快的磁盘或使用 RAID,读取图像序列的最快方法是什么?

将它们全部放在一个大的 tar 文件中(并使用自定义解压缩代码读取它们),而不是作为文件夹中的单个文件会更快吗?

我找不到PNG解码的多线程实现,所以这个阶段也可能成为瓶颈。使用 WebP 而不是 PNG 会提供额外的速度优势吗?

我应该考虑/评估哪些其他想法?

rod*_*gob 6

亲爱的堆栈溢出社区,

正如这里所承诺的,这是根据您的许多建议进行的实验的结果。特别感谢@user894763 如何让我走上“正确的道路”。

tl;dr在未压缩的 tar 中使用 pnm 文件(是的,我说的是 pnm!)。

我在两台高端机器上做了实验,一台使用 SSD 磁盘,另一台使用网络文件系统。两者都具有高端 CPU,但在磁盘访问方面表现出“频谱的两端”。令人惊讶的是,两台机器的结论是相同的。我只报告一组结果(对于后一种情况)。两个实验中文件格式之间的比率几乎相同。

从这些实验中我学到了两件重要的事情:

  • 当考虑来自磁盘的文件时,操作系统磁盘缓存是最重要的(即操作系统尽可能将文件操作保存在 RAM 而不是物理设备中,并且它在这方面做得非常好)。
  • 与我最初的猜测相反,从磁盘读取图像是 CPU 受限操作,而不是 I/O 受限操作。

实验方案

我正在按固定顺序读取一组约 1200 个图像,不对图像进行任何计算,我只是测量将像素加载到内存中的时间。pnm 格式的 tar 文件大小约为 600 MB,png 格式的 tar 文件大小约为 300 MB,webp 格式的 tar 文件大小约为 200 MB。

“新读”是指在机器上完成的第一次读取。
“缓存读取”是指在同一台计算机上完成的第二次读取(以及任何后续读取)。

所有数字大约为+/- 10 Hz。

webp fresh read: 30 Hz
webp cached read: 80 Hz

webp + tar fresh read: 100 Hz
webp + tar cached read: 100 Hz

png fresh read:  50 Hz
png cached read: 165 Hz

png + tar fresh read: 200 Hz
png + tar cached read: 200 Hz

pnm fresh read: 50 Hz
pnm cached read: 600 Hz

pnm + tar fresh read: 200 Hz
pnm + tar cached read: 2300 Hz
Run Code Online (Sandbox Code Playgroud)

笔记

有人告诉我也许有办法改变 webp 压缩参数以使解压更快。我怀疑它仍然无法匹配 pnm 性能。

请注意,我使用自定义代码来读取 tar 文件中的图像,该文件是从磁盘“逐个图像”读取的。

我不知道为什么读取“新鲜”的 webp 图像比 png 图像慢,我只能推测网络磁盘系统有一些“内部”缓存,在某种程度上改变了行为。不过这并不影响上课。

教训

  1. 如果您要多次读取一个文件(或一组文件),操作系统磁盘缓存将使所有未来的读取基本上“与从 RAM 读取一样快”。

  2. 即使从磁盘读取,解压缩图像的时间也是不可忽略的。

  3. 将所有文件放入单个未压缩(tar)文件中,可以显着加快速度,因为操作系统会假设将读取整个文件,甚至在我们访问未来图像之前就预先加载它们。当简单地读取文件夹内的内容时,这似乎不会发生。

  4. 如果小心谨慎,从磁盘读取图像序列时(特别是重复读取时)可以获得 4x ~ x10 倍的加速。