C#将对象序列化为xml字符串的最快方法

时间:2017-07-03 21:33:29

标签: c# .net xml linq-to-xml xml-serialization

背景:我的任务是将C#对象序列化为xml字符串。然后将xml字符串传递给webservice并将其写入xml文件中的磁盘。序列化的任务需要在流程获得的5分钟时间内完成。使用者webservice只接受字符串作为xml。 我一直在研究从xml serialiser,xmlwriter,xdocument,stringbuilder创建xml字符串以编写xml字符串,对象到json到xml,linq到xml的各种方法,但我需要知道是否有人有类似的经历。主要目的是拥有一个高性能的xml字符串,它不像在字符串中创建xml那样冗长和容易出错。

我的对象叫做员工,有18个字符串/日期属性。对象在内存中创建,一旦进程启动,我们总共获得大约4000k个对象。该过程每天运行1小时,从数据文件加载数据并创建人员对象。对对象执行许多功能。一旦对象准备就绪,就需要对它们进行序列化,并将xml中的数据发送到webservice并写入xml文件。简而言之,这些对象需要序列化并保存到磁盘并发送到Web服务。

有没有人推荐任何高性能但易于使用。保持方法?抱歉没有任何代码,因为我可以创建一个类并添加xml序列化器等代码,但我不认为它会增加任何价值,因为目前我正在寻找过去的经验加上我想确保我不会去一只野鹅追逐并希望用正确的解决方案实施。

我尝试过以下序列化代码,但需要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 个答案:

答案 0 :(得分:3)

根据您的要求,速度是最苛刻的部分。我们需要在这里写一个基准。正如评论中所提到的,除XmlSerializer之外,我们可以将DataContractSerializer用于我们的目的。有几个Q&amp; A与这两者之间的差异有关,例如:

  1. DataContractSerializer vs XmlSerializer: Pros and Cons of each serializer
  2. Linq to Xml VS XmlSerializer VS DataContractSerializer
  3. Difference between DataContractSerializer vs XmlSerializer
  4. 其他选项是使用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; }
    }
    

    并且所有属性都具有值(非null),在调用序列化程序之前分配。序列化代码如下所示:

        //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。结果可能因环境而异,您应该制定自己的基准。