.NET二进制文件读取性能
我有一个非常大的二进制文件集,其中几千个原始视频帧正在顺序读取和处理,我现在正在寻找优化它,因为它似乎是更CPU的约束比I/O限制。.NET二进制文件读取性能
目前正在读这样的框架,我怀疑这是最大的罪魁祸首:
private byte[] frameBuf;
BinaryReader binRead = new BinaryReader(FS);
// Initialize a new buffer of sizeof(frame)
frameBuf = new byte[VARIABLE_BUFFER_SIZE];
//Read sizeof(frame) bytes from the file
frameBuf = binRead.ReadBytes(VARIABLE_BUFFER_SIZE);
难道多大的差别在.NET重新组织的I/O,以避免用每一帧创建所有这些新的字节数组?
我对.NET的内存分配机制的理解很薄弱,因为我来自纯C/C++背景。我的想法是重新写这个来共享一个静态缓冲类,它包含一个非常大的共享缓冲区,其中包含一个整数来跟踪帧的实际大小,但我喜欢当前实现的简单性和可读性,并且宁愿保留它CLR已经以某种我不知道的方式处理这个问题。
任何输入,将不胜感激。
如果您使用binRead.ReadBytes
,则不需要初始化frameBuf
- 您将返回一个新的字节数组,它将覆盖刚创建的字节数组。尽管如此,这确实会为每次读取创建一个新数组。
如果你想避免创建一堆字节数组,你可以使用binRead.Read
,这将把字节放到你提供给它的数组中。但是,如果其他线程正在使用该阵列,他们会看到它的内容正好在它们的前面。确保您可以保证在重新使用之前完成缓冲区。
感谢您指出 - 我相信我的冗余分配会显着降低这一点。静态共享数组正是我正在考虑的内容,但如果性能增益与创建字节数组相比并不大,那么我宁愿坚持使用优雅的解决方案来处理与您概述的相同的复杂问题(共享访问) 。 – rnd 2010-08-18 20:21:00
你需要小心这里。在这样的代码上获得完全虚假的测试结果是非常容易的,这种结果在实际使用中从不复制。问题在于文件系统缓存,它会缓存从文件中读取的数据。当您重复运行测试,调整代码并寻找改进时,麻烦就开始了。
第二次,随后您运行测试,数据不再脱离磁盘。它仍然存在于缓存中,它只需要一个从内存到内存的拷贝就可以将它放到你的程序中。这非常快,大约需要几微秒的开销和复制所需的时间。它以总线速度运行,现代机器至少每秒5千兆字节。
现在,您的测试将显示您花费大量时间分配缓冲区并处理数据,相对于读取数据所花费的时间。
这在实际使用中很少再现。数据将不会在缓存中,现在流氓磁盘驱动器需要查找数据(很多毫秒),需要从磁盘上读取数据(每秒几十兆字节)。现在读取数据需要四个时间长度中的三个。如果你设法让处理步骤快两倍,你的程序实际上只会运行速度提高0.05%。给或拿。
这是一个很好的观点,但是我正在对数据集运行我的测试,这个测试数据集将我的机器内存压缩了几个千兆字节。我担心的是,旧C++库中的类似代码将在不到一半的时间内处理这个数据集。但是,我注意到这个配置文件警告说每个/ s大约有2,826个页面正在写入磁盘,并且该应用程序可能会受到内存限制。我没有明确地处理这些数组 - 这些可以在GC取消分配之前缓存吗? – rnd 2010-08-18 20:46:00
这些缓冲区可能很大,大于85KB。哪些让他们分配在蕙。他们会在那里停留一段时间,它需要一个第2代收藏。没有任何东西是免费的,当它们很大时重用缓冲区也是.NET的一个好策略。 – 2010-08-18 20:51:43
如果您想强制文件从磁盘加载,请清除Windows文件缓存,如以下问题所示:http://stackoverflow.com/q/478340/80525 – BKewl 2014-02-05 20:10:31
您是否运行了一个分析器来确保性能命中并不来自其他来源?还是你刚刚去了,假设“这可能是它”? – 2010-08-18 19:11:12
嗨大卫, 我跑了几次性能分析器,这种方法是我最昂贵的一个。因此,我期待看看这个“新的字节[]”方法在.NET中是否是一个明显的性能杀手。作为一名C程序员,这看起来与每个缓冲区的数千个“malloc”语句类似,肯定会比重用缓冲区慢。 – rnd 2010-08-18 20:16:59