簡體   English   中英

C#將對象序列化為xml字符串的最快方法

[英]C# fastest way to serialise object to xml string

背景:我的任務是將C#對象序列化為xml字符串。 然后將xml字符串傳遞給webservice,並以xml文件的形式寫入磁盤。 序列化任務需要在該過程獲得的5分鍾內完成。 使用者Web服務僅接受字符串作為xml。 我一直在研究從xml序列化器,xmlwriter,xdocument,stringbuilder編寫xml字符串,對象到json到xml,linq到xml的創建xml字符串的各種方式,但是我需要知道是否有人有做類似事情的經驗。 主要目標是擁有一個高性能的xml字符串,它不像在字符串中創建xml那樣冗長且容易出錯。

我的對象叫Employee,有18個字符串/日期屬性。 這些對象是在內存中創建的,一旦啟動,我們總共可以得到4000k對象。 該過程每天運行1個小時,從數據文件中加載數據並創建人員對象。 在對象上執行許多功能。 對象准備就緒后,需要對其進行序列化,並將xml中的數據發送到webservice並將其寫入xml文件。 簡而言之,這些對象需要序列化並保存到磁盤並發送到Webservice。

有沒有人推薦任何高性能但又容易做到的。 保持方法? 抱歉不放置任何代碼,因為我可以創建一個類並添加xml serialiser等代碼,但由於當前我正在尋找過去的經驗,我不認為此刻會增加任何價值,而且我想確保自己不會過失追逐並想以正確的解決方案實施。

我嘗試了以下序列化程序代碼,但是序列化所有4000k對象需要10分鍾以上的時間。

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;
    }
}

我也嘗試過緩存序列化器,但是沒有任何性能上的改進

根據您的要求,速度是最苛刻的部分。 我們需要在此處編寫一個基准。 如評論中所述,除了XmlSerializer之外,我們還可以使用DataContractSerializer來達到目的。 與這兩者之間的區別有關的一些問答,例如:

  1. DataContractSerializer與XmlSerializer:每個序列化器的優缺點
  2. Linq到Xml VS XmlSerializer VS DataContractSerializer
  3. DataContractSerializer和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; }
}

並且所有屬性都有值(非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在要求之內,與XmlSerializer相比,處理時間為30-45% 結果可能因環境而異,因此您應該制定自己的基准。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM