草庐IT

c++ - 读取一系列图像的最快方法是什么?

coder 2024-02-16 原文

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

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

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

Other than buying faster disks, or using RAID, what is the fastest way to read a sequence of images ?

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

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

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

最佳答案

亲爱的堆栈溢出社区,

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

tl;dr use pnm files inside an uncompressed tar (yes I said pnm !).

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

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

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

实验方案

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

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

所有数字大约为 +- 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

注意事项

有人告诉我,也许可以通过更改 webp 压缩参数来加快解压速度。我怀疑它仍然无法匹配 pnm 性能。

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

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

类(class)

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

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

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

  4. 如果注意得当,从磁盘读取一系列图像时(特别是重复读取时)可以获得 4x ~ x10 倍的加速。

关于c++ - 读取一系列图像的最快方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16610318/

有关c++ - 读取一系列图像的最快方法是什么?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  5. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  6. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. Ruby 方法() 方法 - 2

    我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby​​-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco

  9. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  10. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

随机推荐