次の方法で共有


SYSK 320: Binary vs. xml serialization performance

In my post SYSK 315 (http://blogs.msdn.com/irenak/archive/2007/03/27/sysk-315-generic-functions-for-object-xml-serialization-deserialization.aspx) I shared two generic functions for serialization and de-serialization of any object to/from xml.

 

Reader Doug was wondering on the performance of those methods. So, here is my response:

 

On my Toshiba Tecra M5 (dual 2Ghz processor, 2Gb memory) an object of type List<object[]> containing 296 “rows” and 18 “columns” with elements of different data types (strings, integers, dates, etc.) takes approximately 14 ms per iteration for binary serialization & de-serialization and 31 ms per iteration for xml serialization & de-serialization.

 

Summary: My tests show that, on average, xml serialization is roughly twice that of binary serialization (i.e. binary serialization takes half the time compared to xml serialization).

 

Note: Serialization performance depends on the complexity of the object, so you should do your own tests to get more precise results for your situation.

 

 

******************************************************************

Here is the code I used:

private void button1_Click(object sender, EventArgs e)

{

List<object[]> data = new List<object[]>();

using (System.Data.SqlClient.SqlConnection cn = new System.Data.SqlClient.SqlConnection("Persist Security Info=False;Integrated Security=SSPI;database=AdventureWorks;server=(local);"))

{

cn.Open();

System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(

"select E.EmployeeID, E.NationalIDNUmber, E.LoginID, E.Title, E.ManagerID, E.BirthDate, E.MaritalStatus, E.Gender," +

"E.HireDate, E.SalariedFlag, E.VacationHours, E.SickLeaveHours, " +

"D.Name, D.GroupName, A.AddressLine1, A.AddressLine2, A.City, A.PostalCode " +

"from HumanResources.Employee E " +

"inner join HumanResources.EmployeeDepartmentHistory ED on ED.EmployeeID = E.EmployeeID " +

"inner join HumanResources.Department D on ED.DepartmentID = D.DepartmentID " +

"inner join HumanResources.EmployeeAddress EA on E.EmployeeID = EA.EmployeeID " +

"inner join Person.Address A on EA.AddressID = A.AddressID " +

"where E.CurrentFlag = 1",

cn);

using (System.Data.SqlClient.SqlDataReader dr = cmd.ExecuteReader())

{

while (dr.Read())

{

object[] row = new object[dr.FieldCount];

dr.GetValues(row);

data.Add(row);

}

}

}

// Replace DBNull

foreach (object[] row in data)

{

for (int i = 0; i < row.Length; i++)

{

if (row[i] is DBNull)

{

row[i] = null;

}

}

}

System.Diagnostics.Stopwatch swXml = new System.Diagnostics.Stopwatch();

System.Diagnostics.Stopwatch swBinary = new System.Diagnostics.Stopwatch();

for (int i = 0; i < 500; i++)

{

swXml.Start();

string xml = ToXml<List<object[]>>(data);

List<object[]> fromXml = FromXml<List<object[]>>(xml);

swXml.Stop();

swBinary.Start();

string binary = ToBinary<List<object[]>>(data);

List<object[]> fromBinary = FromBinary<List<object[]>>(binary);

swBinary.Stop();

}

System.Diagnostics.Debug.WriteLine(string.Format("Xml serialization: {0} ms", swXml.ElapsedMilliseconds));

System.Diagnostics.Debug.WriteLine(string.Format("Binary serialization: {0} ms", swBinary.ElapsedMilliseconds));

}

public static string ToXml<T>(T source)

{

string result = null;

using (System.IO.StringWriter sw = new System.IO.StringWriter())

{

using (System.Xml.XmlWriter writer = System.Xml.XmlTextWriter.Create(sw, null))

{

System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));

serializer.Serialize(writer, source);

}

result = sw.ToString();

}

return result;

}

public static T FromXml<T>(string xml)

{

T result = default(T);

if (string.IsNullOrEmpty(xml) == false)

{

using (System.IO.StringReader sr = new System.IO.StringReader(xml))

{

System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));

result = (T)serializer.Deserialize(sr);

}

}

return result;

}

public static string ToBinary<T>(T source)

{

string result = null;

using (System.IO.MemoryStream ms = new System.IO.MemoryStream())

{

System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

formatter.Serialize(ms, source);

ms.Position = 0;

byte[] data = ms.GetBuffer();

result = System.Text.UnicodeEncoding.Default.GetString(data);

}

return result;

}

public static T FromBinary<T>(string data)

{

T result = default(T);

if (string.IsNullOrEmpty(data) == false)

{

using (System.IO.MemoryStream ms = new System.IO.MemoryStream(System.Text.UnicodeEncoding.Default.GetBytes(data)))

{

System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

result = (T) formatter.Deserialize(ms);

}

}

return result;

}

Comments

  • Anonymous
    April 03, 2007
    Thanks for the sample and the measurements. The builtin serialization offer ease of use and stability. It is good to see an example of how to measure the cost.

  • Anonymous
    April 03, 2007
    Doug, This is a partial measurement of "cost".  For a more complete view of resource usage, you'll need to also consider memory and CPU utilization.

  • Anonymous
    April 05, 2007
    I ran a similar test recently to compare the performance of remoting vs webservice. We have a series of webservices that perform reasonably well. Still, we wanted to try and go fatser, so we coded a remoting server that exposed the same interface as the webservices. To my astonishment, the remoting with binary serialization over tcp was A LOT SLOWER than plain webservice calls. After a lot of checking, we found out that the performance killer was Xml attributes attached to the transport objects. For example: [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://ns.hr-xml.org/2004-08-02")] [System.Xml.Serialization.XmlRootAttribute("TimeCard", Namespace="http://ns.hr-xml.org/2004-08-02", IsNullable=false)] public class TimeCardType {    [System.Xml.Serialization.XmlElementAttribute("ReportedTime")]    public TimeCardTypeReportedTime[] ReportedTime; ... The reason why we have these attributes is to be completely Hr-Xml compliant. We do not have any choice in the matter. Do you have any experience with this?