我想为性能关键的应用程序反序列化 100 万对 (String,Guid) 的列表。格式可以是我选择的任何格式,并且序列化没有相同的性能要求。
哪种方法最好?文本还是二进制?连续写每一对(字符串,guid),还是写所有字符串后跟所有guid?
我开始使用 LinqPad(以及仅反序列化字符串的更简单示例)并发现(有点违反直觉),使用 a TextReader
andReadLine()
比使用 a BinaryReader
and快很多ReadString()
。(文件系统缓存是否在欺骗我?)
public string[] DeSerializeBinary()
{
var tmr = System.Diagnostics.Stopwatch.StartNew();
long ms = 0;
string[] arr = null;
using (var rdr = new BinaryReader(new FileStream(file, FileMode.Open, FileAccess.Read)))
{
var num = rdr.ReadInt32();
arr = new String[num];
for (int i = 0; i < num; i++)
{
arr[i] = rdr.ReadString();
}
tmr.Stop();
ms = tmr.ElapsedMilliseconds;
Console.WriteLine("DeSerializeBinary took {0}ms", ms);
}
return arr;
}
public string[] DeserializeText()
{
var tmr = System.Diagnostics.Stopwatch.StartNew();
long ms = 0;
string[] arr = null;
using (var rdr = File.OpenText(file))
{
var num = Int32.Parse(rdr.ReadLine());
arr = new String[num];
for (int i = 0; i < num; i++)
{
arr[i] = rdr.ReadLine();
}
tmr.Stop();
ms = tmr.ElapsedMilliseconds;
Console.WriteLine("DeserializeText took {0}ms", ms);
}
return arr;
}
一些编辑:
- 我使用 RamMap 来清除文件系统缓存,结果发现文本和二进制阅读器仅对字符串几乎没有区别。
- 我有一个相当简单的类来保存字符串和 guid。它还拥有一个 int 索引,该索引对应于它在列表中的位置。显然没有必要在序列化中包含这个。
- 在(二进制)反序列化字符串和 Guid 的测试中,我得到了大约 500 毫秒。
- 理想的时间是 50 毫秒,或者尽可能接近。然而,一个简单的实验表明,将(压缩的)文件从相当快的 SSD 驱动器读取到内存中至少需要 120 毫秒,而根本不需要任何类型的解析。所以 50ms 似乎不太可能。
- 我们的字符串没有理论上的长度限制。但是,我们可以假设性能目标仅适用于它们全部为 20 个字符或更少的情况。
- 时间包括打开文件。
读取字符串现在是明显的瓶颈(因此我只尝试序列化字符串)。在我预先分配一个 16 字节的数组来读取 GUID 之前,JIT_NewFast 占用了 30%。