C# .NET二进制文件读取性能

C# .NET二进制文件读取性能,c#,.net,performance,file,binary,C#,.net,Performance,File,Binary,我有一个非常大的二进制文件集,其中数千个原始视频帧正在被顺序读取和处理,我现在正在寻求对其进行优化,因为它似乎比I/O更受CPU限制 目前正在以这种方式读取帧,我怀疑这是最大的罪魁祸首: private byte[] frameBuf; BinaryReader binRead = new BinaryReader(FS); // Initialize a new buffer of sizeof(frame) frameBuf = new byte[VARIABLE_BUFFER_S

我有一个非常大的二进制文件集,其中数千个原始视频帧正在被顺序读取和处理,我现在正在寻求对其进行优化,因为它似乎比I/O更受CPU限制

目前正在以这种方式读取帧,我怀疑这是最大的罪魁祸首:

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
,这将把字节放入您提供给它的数组中。但是,如果其他线程正在使用该数组,它们将看到它的内容在它们面前发生变化。在重复使用缓冲区之前,请确保您已经完成了缓冲区的使用。

在这里您需要小心。在这样的代码上很容易得到完全虚假的测试结果,这些结果在实际使用中从未重新编程过。问题在于文件系统缓存,它将缓存从文件读取的数据。当您反复运行测试、调整代码并寻求改进时,问题就开始了

第二次,以及以后运行测试时,数据不再从磁盘中流出。它仍然存在于缓存中,只需要一个内存到内存的拷贝就可以将其放入程序中。这非常快,一微秒左右的开销加上复制所需的时间。它以总线速度运行,在现代机器上至少每秒5千兆字节

您的测试现在将显示您在分配缓冲区和处理数据上花费了大量时间,相对于读取数据所花费的时间


这在实际使用中很少会重新编程。数据还不会在缓存中,现在缓慢的磁盘驱动器需要查找数据(许多毫秒),并且需要从磁盘盘中读取数据(最多每秒几十兆字节)。现在读取数据需要四个数量级中的三个时间更长。如果您设法使处理步骤的速度提高两倍,那么您的程序实际运行速度只会提高0.05%。给予或接受。

您是否运行了探查器,以确保性能不受其他来源的影响?或者你只是去假设“可能就是这样”?嗨,大卫,我在上面运行了几次性能分析器,这个方法是我最昂贵的方法。因此,我想看看这个“新字节[]”方法是否是.NET中的一个明显的性能杀手。作为一个C程序员,这看起来类似于每个缓冲区的数千条“malloc”语句,这肯定比重复使用的缓冲区慢。感谢您指出这一点——我确信我的冗余分配正在明显地降低速度。静态共享阵列正是我所考虑的,但如果与创建字节阵列相比性能增益不大,我更愿意使用优雅的解决方案来解决与您概述的相同的复杂问题(共享访问)。这是一个很好的观点,然而,我在一个数据集上运行我的测试,这个数据集使我的机器的内存相形见绌。我担心的是,在我的旧C++库中,类似的代码将在不到一半的时间内处理这个数据集。但是,我注意到配置文件警告说,大约每秒2826页正在写入磁盘,并且应用程序可能内存不足。我没有明确地处理这些数组中的任何一个-这些数组是否可以在GC取消分配它们之前得到缓存?这些缓冲区可能很大,超过85KB。这使得他们被分配到LOH中。它们将在那里停留一段时间,需要第2代的收集。没有任何东西是免费的,在.NET中,当缓冲区较大时重用缓冲区也是一个很好的策略。如果要强制从磁盘加载文件,请清除Windows文件缓存,如本问题所示: