循环读写文件时,访问Stream的Length/Position属性是否影响性能?
BinaryReader两种循环读取方式的性能差异原因
以下是两种读取实现代码:
// Case 1 while(true) { int packetLength = GetPacketLength(); byte[] data = br.ReadBytes(packetLength); if(data.Length < packetLength) { Console.Write("end"); break; } } // Case2 while(true) { int packetLength = GetPacketLength(); if(stream.Length - stream.Position < packetLength) { Console.Write("end"); break; } byte[] data = br.ReadBytes(packetLength); }
我发现用BinaryReader循环数千次读取并处理文件时,Case 1的运行速度远快于Case 2。目前已经采用Case 1的写法,但好奇Case 2速度较慢的原因,特此提问。
性能差异的核心原因
stream.Length的系统调用开销:针对文件流,每次获取Length属性都需要向操作系统发起系统调用,查询文件的总大小。循环数千次就意味着要执行数千次额外的系统调用,这会产生显著的性能损耗,而Case 1完全跳过了这一步。- 额外的属性读取与计算:Case 2每次循环都要读取
stream.Length和stream.Position两个属性,再执行减法运算做判断。相比Case 1直接利用ReadBytes返回的数组长度做校验,多了好几步无意义的额外操作。 ReadBytes的内部优化:BinaryReader.ReadBytes本身已经做了高效读取的内部优化,返回的数组长度就是实际读取到的字节数。Case 1直接复用这个结果做终止判断,完全不需要额外查询流的状态。- 缓存命中率的影响:频繁查询流的
Length和Position可能会干扰文件系统的缓存逻辑,导致数据读取时的缓存命中率下降,进一步拖慢整体运行速度。
内容的提问来源于stack exchange,提问作者seonguk.jeon
相关产品推荐
相关产品推荐

