2017-07-03 100 views
0

背景:我一直负责序列化的C#对象转换为XML字符串。然后将xml字符串传递给webservice并以xml文件形式写入磁盘。序列化任务需要在过程得到的5分钟内完成。消费者web服务只接受字符串作为xml。 我一直在研究从xml serialiser,xmlwriter,xdocument,stringbuilder创建xml字符串的各种方式来编写xml字符串,将对象转换为json转换为xml,将linq转换为xml,但是我需要知道是否有人有过类似的经验。主要目的是要具有较高的高性能XML字符串事实并非如此冗长且容易出错的像字符串创建XML。C#最快的方式序列化对象到XML字符串

我的对象被称为Employee和具有18串/日期属性。这些对象是在内存中创建的,一旦进程启动,我们总共可以获得大约4000k的对象。该过程每天运行1小时,从数据文件加载数据并创建人员对象。许多功能都在对象上执行。一旦对象是准备好了,他们需要被序列化和XML数据被发送到web服务,并writren到XML文件。简而言之,这些对象需要序列化并保存到磁盘并发送到webservice。

有谁推荐任何高高性能且易于。维护方法?道歉没有定位任何代码,因为我可以创建一个类并添加xml serialiser等代码,但我不认为它会增加任何价值,因为目前我正在寻找过去的经验,另外我想确保我不会去野雁追逐并希望用正确的解决方案来实施。

我尝试过以下serialiser码,但它需要10多分钟来串行化所有4000k对象。

public static bool Serialize<T>(T value, ref string serializeXml) 
{ 
    if (value == null) 
    { 
     return false; 
    } 
    try 
    { 
     XmlSerializer xmlserializer = new XmlSerializer(typeof(T)); 
     StringWriter stringWriter = new StringWriter(); 
     XmlWriter writer = XmlWriter.Create(stringWriter); 

     xmlserializer.Serialize(writer, value); 

     serializeXml = stringWriter.ToString(); 

     writer.Close(); 
     return true; 
    } 
    catch (Exception ex) 
    { 
     return false; 
    } 
} 

我也曾尝试缓存串行器,但是没有得到任何的性能提升

+1

为什么你需要它作为字符串?为什么不使用流?另外,缓存你的XmlSerializer实例。它消耗了大量的内存,并且可以重复使用。 – eocron

+0

我试过缓存但没有结果。需要是一个字符串,所以我可以发送到webservice。 – InfoLearner

+0

你不能发送它作为流? – eocron

回答

3

根据您的要求,速度是最苛刻的一部分。我们需要在这里写一个基准。正如评论中提到的,除了XmlSerializer之外,我们可以使用DataContractSerializer来达到我们的目的。有几个Q &一个相关的这两个之间的区别,例如:

  1. DataContractSerializer vs XmlSerializer: Pros and Cons of each serializer
  2. Linq to Xml VS XmlSerializer VS DataContractSerializer
  3. Difference between DataContractSerializer vs XmlSerializer

另一个选项是使用手动StringBuilderXmlWriter写你的XML两种。虽然你提到的要求:

主要目的是要具有较高的高性能XML字符串,它是不那么冗长且容易出错的像串

这三个串行加入比较创建XML。当然,在StringBuilder的情况下,文本必须转义。在这里,我用了System.Security.SecurityElement.Escape。要序列化的对象如下所示:

//Simple POCO with 11 String properties, 7 DateTime properties 
[DataContractAttribute()] 
public class Employee 
{ 
    [DataMember()] 
    public string FirstName { set; get; } 
    [DataMember()] 
    public string LastName { set; get; } 
    //...omitted for clarity 
    [DataMember()] 
    public DateTime Date03 { set; get; } 
    [DataMember()] 
    public DateTime Date04 { set; get; } 
} 

并且所有属性都有值(非空),在调用序列化程序之前分配。该串行代码看起来像:

//Serialize using XmlSerializer 
public static bool Serialize<T>(T value, ref StringBuilder sb) 
{ 
    if (value == null) 
     return false; 
    try 
    { 
     XmlSerializer xmlserializer = new XmlSerializer(typeof(T)); 
     using (XmlWriter writer = XmlWriter.Create(sb)) 
     { 
      xmlserializer.Serialize(writer, value); 
      writer.Close(); 
     } 
     return true; 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex); 
     return false; 
    } 
} 

//Serialize using DataContractSerializer 
public static bool SerializeDataContract<T>(T value, ref StringBuilder sb) 
{ 
    if (value == null) 
     return false; 
    try 
    { 
     DataContractSerializer xmlserializer = new DataContractSerializer(typeof(T)); 
     using (XmlWriter writer = XmlWriter.Create(sb)) 
     { 
      xmlserializer.WriteObject(writer, value); 
      writer.Close(); 
     } 
     return true; 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex); 
     return false; 
    } 
} 

//Serialize using StringBuilder 
public static bool SerializeStringBuilder(Employee obj, ref StringBuilder sb) 
    { 
     if (obj == null) 
      return false; 

     sb.Append(@"<?xml version=""1.0"" encoding=""utf-16""?>"); 
     sb.Append("<Employee>"); 

     sb.Append("<FirstName>"); 
     sb.Append(SecurityElement.Escape(obj.FirstName)); 
     sb.Append("</FirstName>"); 

     //... Omitted for clarity 

     sb.Append("</Employee>"); 

     return true; 
    } 

//Serialize using XmlSerializer (manually add elements) 
public static bool SerializeManual(Employee obj, ref StringBuilder sb) 
{ 
    if (obj == null) 
     return false; 

    try 
    { 
     using (var xtw = XmlWriter.Create(sb)) 
     { 
      xtw.WriteStartDocument(); 
      xtw.WriteStartElement("Employee"); 

      xtw.WriteStartElement("FirstName"); 
      xtw.WriteString(obj.FirstName); 
      xtw.WriteEndElement(); 

      //...Omitted for clarity 

      xtw.WriteEndElement(); 
      xtw.WriteEndDocument(); 

      xtw.Close(); 
     } 
     return true; 
    } 
    catch(Exception ex) 
    { 
     Console.WriteLine(ex); 
     return false; 
    } 
} 

在基准测试中,4M Employee对象给出的参数和XML写入预分配StringBuilder(参数ref StringBuilder sb)。对于DataContractSerializerManual XmlWriter,还执行了与Parallel.Invoke(3个并行任务)的基准测试。所需的处理时间为每串:

//Simple POCO with 11 String properties, 7 DateTime properties 
XmlSerializer   =00:02:37.8151125 = 157 sec: 100% (reference) 
DataContractSerializer=00:01:10.3384361 = 70 sec: 45% (3-Parallel: 47sec = 30%) 
StringBuilder   =00:01:22.5742122 = 82 sec: 52% 
Manual XmlWriter  =00:00:57.8436860 = 58 sec: 37% (3-Parallel: 40sec = 25%) 

环境:.Net Framework 4.5.2, Intel(R) Core(TM) i5-3337U @ 1.80GHz 1.80GHz, Windows 10, 6.0GB Memory。我预计StringBuilder将是最快的,但事实并非如此。也许,瓶颈在System.Security.SecurityElement.Escape()

结论:DataContractSerializer在要求范围内,处理时间为30-45%XmlSerializer相比较。结果可能因环境而异,您应该制定自己的基准。