public virtual int ReadInt32()
{
if (this.m_isMemoryStream)
{
MemoryStream stream = this.m_stream as MemoryStream;
return stream.InternalReadInt32();
}
this.FillBuffer(4);
return (((this.m_buffer[0] | (this.m_buffer[1] << 8)) | (this.m_buffer[2] << 0x10)) | (this.m_buffer[3] << 0x18));
}
在我看来,这似乎非常低效,因为计算机的设计是为了使用32位值,自从32位CPU被发明以来。
因此,我自己编写了(不安全的)FastBinaryReader类,并使用了以下代码:
public unsafe class FastBinaryReader :IDisposable
{
private static byte[] buffer = new byte[50];
//private Stream baseStream;
public Stream BaseStream { get; private set; }
public FastBinaryReader(Stream input)
{
BaseStream = input;
}
public int ReadInt32()
{
BaseStream.Read(buffer, 0, 4);
fixed (byte* numRef = &(buffer[0]))
{
return *(((int*)numRef));
}
}
...
}
我成功地将读取一个500MB文件所需的时间缩短了5-7秒,但总体上仍然相当慢(最初需要29秒,现在使用我的FastBinaryReader
大约需要22秒)。
我还是有些困惑,为什么读取这样一个相对较小的文件仍然需要这么长时间。如果我将文件从一个磁盘复制到另一个磁盘,只需要几秒钟,因此磁盘吞吐量不是问题。
我进一步内联了ReadInt32等调用,最终得到了以下代码:
using (var br = new FastBinaryReader(new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000, FileOptions.SequentialScan)))
while (br.BaseStream.Position < br.BaseStream.Length)
{
var doc = DocumentData.Deserialize(br);
docData[doc.InternalId] = doc;
}
}
public static DocumentData Deserialize(FastBinaryReader reader)
{
byte[] buffer = new byte[4 + 4 + 8 + 4 + 4 + 1 + 4];
reader.BaseStream.Read(buffer, 0, buffer.Length);
DocumentData data = new DocumentData();
fixed (byte* numRef = &(buffer[0]))
{
data.InternalId = *((int*)&(numRef[0]));
data.b = *((int*)&(numRef[4]));
data.c = *((long*)&(numRef[8]));
data.d = *((float*)&(numRef[16]));
data.e = *((float*)&(numRef[20]));
data.f = numRef[24];
data.g = *((int*)&(numRef[25]));
}
return data;
}
还有什么更好的想法可以让这个过程更快吗?我在想,也许我可以使用marshalling将整个文件映射到某个自定义结构的内存中,因为数据是线性的、固定大小的和顺序的。
已解决:我得出结论,FileStream的缓冲/BufferedStream存在缺陷。请参见下面的被接受的答案和我的答案(包括解决方案)。