StringBuilder到FileStream与直接FileStream性能
本文关键字:FileStream 性能 StringBuilder | 更新日期: 2023-09-27 18:00:15
我正在向FileStream增量写入大量文本数据,而且速度相当慢。如果我改为将文本写入内存中的StringBuilder,然后将StringBuilder批量转储到FileStream,会更快吗?我认为这样做可能可以利用FileStream中的某种缓冲,但我对FileStream的工作方式了解不够,无法进行判断。
由于我们没有您的序列化代码,并且您怀疑您可以通过使用优化的Stream和/或StringBuilder来获得性能提升,我确实在LinqPad中设置了一个测试装置,以建立一个具有长字符串属性和其他一些属性的类的列表。该列表已序列化到磁盘
Xml序列化后的磁盘大小为115.910.381字节(110 MB)。
试验台
void Main()
{
var list = new List<Test>();
for(int k=0;k<100;k++) list.Add(
new Test { Prop1 = Rnd(), /* random string of 1 MB */
Prop2 =k, Prop3=k*k, Prop4= DateTime.Now});
BinaryFormatter(list);
DataContractJsonSerializer(list);
XmlSerializer(list);
XmlSerializerBuffered(list);
XmlSerializerMemory(list);
XmlSerializerStringBuilder(list);
}
由于Xml序列化程序花费了最多的时间,我决定只在该变体中尝试不同的技术。
直接文件流
void XmlSerializer(List<Test> list)
{
var sw = new Stopwatch();
sw.Start();
var s = new FileStream("c:''temp''test.xml", FileMode.Create);
var x = new XmlSerializer(typeof(List<Test>));
x.Serialize(s,list);
s.Close();
sw.Stop();
sw.Elapsed.Dump("Xml");
}
缓冲流
void XmlSerializerBuffered(List<Test> list)
{
var sw = new Stopwatch();
sw.Start();
var s = new FileStream("c:''temp''test.xmlbuf", FileMode.Create);
var b = new BufferedStream(s);
var x = new XmlSerializer(typeof(List<Test>));
x.Serialize(b,list);
b.Close();
s.Close();
sw.Stop();
sw.Elapsed.Dump("Xml Buffered");
}
首先在MemoryStream中,然后复制
void XmlSerializerMemory(List<Test> list)
{
var sw = new Stopwatch();
sw.Start();
var s = new FileStream("c:''temp''test.xmlmem", FileMode.Create);
var m = new MemoryStream(1024*1024); // INITIAL BUFFER SIZE (can and will grow!)
// also works but is slower: var m = new MemoryStream();
var x = new XmlSerializer(typeof(List<Test>));
x.Serialize(m,list);
m.Position=0;
m.CopyTo(s);
m.Close();
s.Close();
sw.Stop();
sw.Elapsed.Dump("Xml Mem");
}
StringBuilder
void XmlSerializerStringBuilder(List<Test> list)
{
var sw = new Stopwatch();
sw.Start();
var s = new StreamWriter("c:''temp''test.xmlsb");
var sb = new StringBuilder();
var m = new StringWriter(sb);
var x = new XmlSerializer(typeof(List<Test>));
x.Serialize(m,list);
s.Write(sb.ToString()); // http://stackoverflow.com/a/5027483/578411
s.Close();
sw.Stop();
sw.Elapsed.Dump("Xml StringBuilder");
}
我的结果(在Win7(64位)/.Net 4.0/x86/4GB/RAID 0+1上)
一个典型的结果是这样的:
Xml 00:00:01.5116768
Xml Buffered 00:00:01.3149263
Xml Mem 00:00:01.2465760
Xml StringBuilder 00:00:02.1440784
所有数据首先写入内存流,然后一次性复制到流的变体总是最快的
StringBuilder总是最慢的,但XmlSerializer中没有重载可以直接"写入"StrigBuilder。因此,使用StringWriter作为额外的间接寻址,这需要时间。
现在请记住,这只是一个丑陋的未优化测试代码,只是为了了解哪种可能有效。仅根据您的数据设置中的实际性能数据进行优化。一次换一件东西,然后继续测量。
数据类
[Serializable]
public class Test
{
public string Prop1 {get; set;}
public int Prop2 {get;set;}
public double Prop3 {get;set;}
public DateTime Prop4 {get;set;}
}
StringBuilder可以帮助您减少创建的字符串数量。如果您在文件流中写入了许多独特的字符串,这可能会产生一些实际的开销。与您讨论字符串连接时的讨论相同(请参阅连接字符串的最有效方法?)。在这种情况下,您认为糟糕的性能可能不是FileStream。
最好的做法是什么?运行性能分析工具。