在编写一个简单的库来解析游戏的数据文件时,我注意到将整个数据文件读入内存并从那里解析明显更快(高达 15 倍,106 秒 v 7 秒)。
解析通常是顺序的,但会不时进行查找以读取存储在文件中其他位置的一些数据,这些数据由偏移量链接。
我意识到从内存中解析肯定会更快,但是如果差异如此显着,那就错了。我写了一些代码来模拟这个:
public static void Main(string[] args)
{
Stopwatch n = new Stopwatch();
n.Start();
byte[] b = File.ReadAllBytes(@"D:\Path\To\Large\File");
using (MemoryStream s = new MemoryStream(b, false))
RandomRead(s);
n.Stop();
Console.WriteLine("Memory read done in {0}.", n.Elapsed);
b = null;
n.Reset();
n.Start();
using (FileStream s = File.Open(@"D:\Path\To\Large\File", FileMode.Open))
RandomRead(s);
n.Stop();
Console.WriteLine("File read done in {0}.", n.Elapsed);
Console.ReadLine();
}
private static void RandomRead(Stream s)
{
// simulate a mostly sequential, but sometimes random, read
using (BinaryReader br = new BinaryReader(s)) {
long l = s.Length;
Random r = new Random();
int c = 0;
while (l > 0) {
l -= br.ReadBytes(r.Next(1, 5)).Length;
if (c++ <= r.Next(10, 15)) continue;
// simulate seeking
long o = s.Position;
s.Position = r.Next(0, (int)s.Length);
l -= br.ReadBytes(r.Next(1, 5)).Length;
s.Position = o;
c = 0;
}
}
}
我使用游戏的一个数据文件作为输入。该文件大约 102 MB,它产生了这个结果 ( Memory read done in 00:00:03.3092618. File read done in 00:00:32.6495245.
),它的内存读取速度比文件快 11 倍。
内存读取是在文件读取之前完成的,以尝试通过文件缓存提高其速度。它仍然慢得多。
我试过增加或减少FileStream
的缓冲区大小;没有什么能产生明显更好的结果,过多地增加或减少它只会使速度变差。
我做错了什么,还是可以预料到的?有什么办法至少可以使经济放缓不那么明显?
为什么一次读取整个文件然后解析它比同时读取和解析要快得多?
我实际上比较了一个用 C++ 编写的类似库,它使用 Windows 本机CreateFileMapping
和MapViewOfFile
读取文件,而且速度非常快。是否是从托管到非托管的不断切换以及导致这种情况的相关编组?
我还尝试MemoryMappedFile
了 .NET 4 中的 s;速度增益只有大约一秒。