2010-11-10 159 views
67

我正在寻找序列化和反序列化.NET对象的最快方法。这是我到目前为止:序列化和反序列化.NET对象的最快方法

public class TD 
{ 
    public List<CT> CTs { get; set; } 
    public List<TE> TEs { get; set; } 
    public string Code { get; set; } 
    public string Message { get; set; } 
    public DateTime StartDate { get; set; } 
    public DateTime EndDate { get; set; } 

    public static string Serialize(List<TD> tData) 
    { 
     var serializer = new XmlSerializer(typeof(List<TD>)); 

     TextWriter writer = new StringWriter(); 
     serializer.Serialize(writer, tData); 

     return writer.ToString(); 
    } 

    public static List<TD> Deserialize(string tData) 
    { 
     var serializer = new XmlSerializer(typeof(List<TD>)); 

     TextReader reader = new StringReader(tData); 

     return (List<TD>)serializer.Deserialize(reader); 
    }   
} 
+2

性能或代码足迹? – ulrichb 2010-11-10 10:34:56

+0

你问我是否需要性能数据或代码? – aron 2010-11-10 10:41:59

+3

他问的是,“最快的方式”,你的意思是在性能或代码占用方面。 BinaryFormatter在代码和实现方面速度非常快,但像Marc这样的解决方案在基准测试中表现更快。 – 2010-11-10 11:54:44

回答

46

下面是使用protobuf-net模型(与发明CTTE)(但保留了能够使用XmlSerializer,这可能是有用的 - 特别是移民);我虚心地提交(有很多证据,如果你需要的话),这个是.NET中速度最快(或者最快)的通用序列化器。

如果你需要字符串,只需base-64编码二进制。

[XmlType] 
public class CT { 
    [XmlElement(Order = 1)] 
    public int Foo { get; set; } 
} 
[XmlType] 
public class TE { 
    [XmlElement(Order = 1)] 
    public int Bar { get; set; } 
} 
[XmlType] 
public class TD { 
    [XmlElement(Order=1)] 
    public List<CT> CTs { get; set; } 
    [XmlElement(Order=2)] 
    public List<TE> TEs { get; set; } 
    [XmlElement(Order = 3)] 
    public string Code { get; set; } 
    [XmlElement(Order = 4)] 
    public string Message { get; set; } 
    [XmlElement(Order = 5)] 
    public DateTime StartDate { get; set; } 
    [XmlElement(Order = 6)] 
    public DateTime EndDate { get; set; } 

    public static byte[] Serialize(List<TD> tData) { 
     using (var ms = new MemoryStream()) { 
      ProtoBuf.Serializer.Serialize(ms, tData); 
      return ms.ToArray(); 
     }    
    } 

    public static List<TD> Deserialize(byte[] tData) { 
     using (var ms = new MemoryStream(tData)) { 
      return ProtoBuf.Serializer.Deserialize<List<TD>>(ms); 
     } 
    } 
} 
+0

感谢Marc努力 – aron 2010-11-10 10:56:56

+1

G'day Marc,热爱您所做的协议缓冲工作,我知道这篇文章已经差不多5年了,但在这里的答案中引用的netserializer(Binoj)有一些指标,表明您的实现不是最快的。这是一个公平的声明/广告还是有一个权衡?谢谢 – 2015-04-15 14:22:21

+0

好吧我现在看到,NetSerialization只适用于相同的版本,因为我正在寻找版本容忍序列化 – 2015-04-15 14:47:18

12

Protobuf是非常非常快。

查看http://code.google.com/p/protobuf-net/wiki/Performance了解有关该系统性能的深入信息和实施。

+0

使用Protobuf有什么缺点吗? – 2010-11-10 10:55:51

+7

你必须注释你的对象。 Protobuf不会像序列化程序那样存储字段名称和类型,而是从实际类型中获取它们。这是目标文件更小的原因之一。文档解释了所有这些。我已经使用它一段时间了,如果你需要快速(de)序列化和小目标文件,protobuf的确是要走的路。 – 2010-11-10 11:03:21

+0

使用C#中的Protobut添加到答案的任何完整的源代码示例? – Kiquenet 2013-02-15 11:59:55

3

.NET中包含的二进制序列化程序应该比XmlSerializer更快。或另一个序列化程序为protobuf,JSON,...

但是对于其中一些你需要添加属性或其他方式添加元数据。例如ProtoBuf在内部使用数字属性ID,并且映射需要通过不同的机制以某种方式保存。任何序列化程序的版本控制都不是微不足道的。

+0

是的,它确实速度非常快,并且它处理比Xml更多的案例/类型。 – leppie 2010-11-10 10:56:01

21
+2

这不是速度。这是缓慢的。它在文章中说“越小越好”。 – 2016-02-01 13:56:14

+1

@TimurNuriyasov,那是时候做的操作 – Maxim 2016-02-01 15:11:38

+2

所以你说二进制是最慢的?我不这么认为!我想它正确地指的是速度,而不是时间。 – Javid 2016-03-12 20:27:50

10

另一个串行在那里,声称自己是超级快一个comprehansive比较是netserializer

在其网站上给出的数据显示,2倍以上的protobuf的表现,我还没试过此我自己,但如果你正在评估各种选项,试试这个以及

+2

我刚刚在我的应用程序中尝试过NetSerializer,它可以创造奇迹。这是值得一试的。 – Galen 2015-06-19 17:54:10

0

你可以尝试Salar.Bois串行其拥有不俗的性能。它的重点是有效载荷的大小,但它也提供了良好的性能。

如果您希望自己查看和比较结果,那么Github页面中有基准测试。

https://github.com/salarcode/Bois

0

我把你的类送入CGbR generator的自由。 由于它处于早期阶段,它不支持DateTime,所以我简单地用它替换了它。生成的序列化的代码如下所示:

public int Size 
{ 
    get 
    { 
     var size = 24; 
     // Add size for collections and strings 
     size += Cts == null ? 0 : Cts.Count * 4; 
     size += Tes == null ? 0 : Tes.Count * 4; 
     size += Code == null ? 0 : Code.Length; 
     size += Message == null ? 0 : Message.Length; 

     return size;    
    } 
} 

public byte[] ToBytes(byte[] bytes, ref int index) 
{ 
    if (index + Size > bytes.Length) 
     throw new ArgumentOutOfRangeException("index", "Object does not fit in array"); 

    // Convert Cts 
    // Two bytes length information for each dimension 
    GeneratorByteConverter.Include((ushort)(Cts == null ? 0 : Cts.Count), bytes, ref index); 
    if (Cts != null) 
    { 
     for(var i = 0; i < Cts.Count; i++) 
     { 
      var value = Cts[i]; 
      value.ToBytes(bytes, ref index); 
     } 
    } 
    // Convert Tes 
    // Two bytes length information for each dimension 
    GeneratorByteConverter.Include((ushort)(Tes == null ? 0 : Tes.Count), bytes, ref index); 
    if (Tes != null) 
    { 
     for(var i = 0; i < Tes.Count; i++) 
     { 
      var value = Tes[i]; 
      value.ToBytes(bytes, ref index); 
     } 
    } 
    // Convert Code 
    GeneratorByteConverter.Include(Code, bytes, ref index); 
    // Convert Message 
    GeneratorByteConverter.Include(Message, bytes, ref index); 
    // Convert StartDate 
    GeneratorByteConverter.Include(StartDate.ToBinary(), bytes, ref index); 
    // Convert EndDate 
    GeneratorByteConverter.Include(EndDate.ToBinary(), bytes, ref index); 
    return bytes; 
} 

public Td FromBytes(byte[] bytes, ref int index) 
{ 
    // Read Cts 
    var ctsLength = GeneratorByteConverter.ToUInt16(bytes, ref index); 
    var tempCts = new List<Ct>(ctsLength); 
    for (var i = 0; i < ctsLength; i++) 
    { 
     var value = new Ct().FromBytes(bytes, ref index); 
     tempCts.Add(value); 
    } 
    Cts = tempCts; 
    // Read Tes 
    var tesLength = GeneratorByteConverter.ToUInt16(bytes, ref index); 
    var tempTes = new List<Te>(tesLength); 
    for (var i = 0; i < tesLength; i++) 
    { 
     var value = new Te().FromBytes(bytes, ref index); 
     tempTes.Add(value); 
    } 
    Tes = tempTes; 
    // Read Code 
    Code = GeneratorByteConverter.GetString(bytes, ref index); 
    // Read Message 
    Message = GeneratorByteConverter.GetString(bytes, ref index); 
    // Read StartDate 
    StartDate = DateTime.FromBinary(GeneratorByteConverter.ToInt64(bytes, ref index)); 
    // Read EndDate 
    EndDate = DateTime.FromBinary(GeneratorByteConverter.ToInt64(bytes, ref index)); 

    return this; 
} 

我创造了这样的采样对象的列表:

var objects = new List<Td>(); 
for (int i = 0; i < 1000; i++) 
{ 
    var obj = new Td 
    { 
     Message = "Hello my friend", 
     Code = "Some code that can be put here", 
     StartDate = DateTime.Now.AddDays(-7), 
     EndDate = DateTime.Now.AddDays(2), 
     Cts = new List<Ct>(), 
     Tes = new List<Te>() 
    }; 
    for (int j = 0; j < 10; j++) 
    { 
     obj.Cts.Add(new Ct { Foo = i * j }); 
     obj.Tes.Add(new Te { Bar = i + j }); 
    } 
    objects.Add(obj); 
} 

我的机器上结果Release编译:

var watch = new Stopwatch(); 
watch.Start(); 
var bytes = BinarySerializer.SerializeMany(objects); 
watch.Stop(); 

尺寸: 149000字节

时间: 2.059ms 3.13ms

编辑:与CGbR开始0.4.3二进制序列化支持的DateTime。不幸的是,DateTime.ToBinary方法非常慢。我会尽快更换它。

EDIT2:当使用UTC DateTime通过在1.669ms调用ToUniversalTime()性能被恢复和时钟英寸

8

对此感兴趣,我决定测试我所能接近的“苹果到苹果”测试的建议方法。我用下面的代码编写了一个控制台应用程序:

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.IO; 
using System.Linq; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Text; 
using System.Threading.Tasks; 

namespace SerializationTests 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var count = 100000; 
      var rnd = new Random(DateTime.UtcNow.GetHashCode()); 
      Console.WriteLine("Generating {0} arrays of data...", count); 
      var arrays = new List<int[]>(); 
      for (int i = 0; i < count; i++) 
      { 
       var elements = rnd.Next(1, 100); 
       var array = new int[elements]; 
       for (int j = 0; j < elements; j++) 
       { 
        array[j] = rnd.Next(); 
       } 
       arrays.Add(array); 
      } 
      Console.WriteLine("Test data generated."); 
      var stopWatch = new Stopwatch(); 

      Console.WriteLine("Testing BinarySerializer..."); 
      var binarySerializer = new BinarySerializer(); 
      var binarySerialized = new List<byte[]>(); 
      var binaryDeserialized = new List<int[]>(); 

      stopWatch.Reset(); 
      stopWatch.Start(); 
      foreach (var array in arrays) 
      { 
       binarySerialized.Add(binarySerializer.Serialize(array)); 
      } 
      stopWatch.Stop(); 
      Console.WriteLine("BinaryFormatter: Serializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds); 

      stopWatch.Reset(); 
      stopWatch.Start(); 
      foreach (var serialized in binarySerialized) 
      { 
       binaryDeserialized.Add(binarySerializer.Deserialize<int[]>(serialized)); 
      } 
      stopWatch.Stop(); 
      Console.WriteLine("BinaryFormatter: Deserializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds); 


      Console.WriteLine(); 
      Console.WriteLine("Testing ProtoBuf serializer..."); 
      var protobufSerializer = new ProtoBufSerializer(); 
      var protobufSerialized = new List<byte[]>(); 
      var protobufDeserialized = new List<int[]>(); 

      stopWatch.Reset(); 
      stopWatch.Start(); 
      foreach (var array in arrays) 
      { 
       protobufSerialized.Add(protobufSerializer.Serialize(array)); 
      } 
      stopWatch.Stop(); 
      Console.WriteLine("ProtoBuf: Serializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds); 

      stopWatch.Reset(); 
      stopWatch.Start(); 
      foreach (var serialized in protobufSerialized) 
      { 
       protobufDeserialized.Add(protobufSerializer.Deserialize<int[]>(serialized)); 
      } 
      stopWatch.Stop(); 
      Console.WriteLine("ProtoBuf: Deserializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds); 

      Console.WriteLine(); 
      Console.WriteLine("Testing NetSerializer serializer..."); 
      var netSerializerSerializer = new ProtoBufSerializer(); 
      var netSerializerSerialized = new List<byte[]>(); 
      var netSerializerDeserialized = new List<int[]>(); 

      stopWatch.Reset(); 
      stopWatch.Start(); 
      foreach (var array in arrays) 
      { 
       netSerializerSerialized.Add(netSerializerSerializer.Serialize(array)); 
      } 
      stopWatch.Stop(); 
      Console.WriteLine("NetSerializer: Serializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds); 

      stopWatch.Reset(); 
      stopWatch.Start(); 
      foreach (var serialized in netSerializerSerialized) 
      { 
       netSerializerDeserialized.Add(netSerializerSerializer.Deserialize<int[]>(serialized)); 
      } 
      stopWatch.Stop(); 
      Console.WriteLine("NetSerializer: Deserializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds); 

      Console.WriteLine("Press any key to end."); 
      Console.ReadKey(); 
     } 

     public class BinarySerializer 
     { 
      private static readonly BinaryFormatter Formatter = new BinaryFormatter(); 

      public byte[] Serialize(object toSerialize) 
      { 
       using (var stream = new MemoryStream()) 
       { 
        Formatter.Serialize(stream, toSerialize); 
        return stream.ToArray(); 
       } 
      } 

      public T Deserialize<T>(byte[] serialized) 
      { 
       using (var stream = new MemoryStream(serialized)) 
       { 
        var result = (T)Formatter.Deserialize(stream); 
        return result; 
       } 
      } 
     } 

     public class ProtoBufSerializer 
     { 
      public byte[] Serialize(object toSerialize) 
      { 
       using (var stream = new MemoryStream()) 
       { 
        ProtoBuf.Serializer.Serialize(stream, toSerialize); 
        return stream.ToArray(); 
       } 
      } 

      public T Deserialize<T>(byte[] serialized) 
      { 
       using (var stream = new MemoryStream(serialized)) 
       { 
        var result = ProtoBuf.Serializer.Deserialize<T>(stream); 
        return result; 
       } 
      } 
     } 

     public class NetSerializer 
     { 
      private static readonly NetSerializer Serializer = new NetSerializer(); 
      public byte[] Serialize(object toSerialize) 
      { 
       return Serializer.Serialize(toSerialize); 
      } 

      public T Deserialize<T>(byte[] serialized) 
      { 
       return Serializer.Deserialize<T>(serialized); 
      } 
     } 
    } 
} 

结果令我感到惊讶;多次运行时,他们是一致的:

Generating 100000 arrays of data... 
Test data generated. 
Testing BinarySerializer... 
BinaryFormatter: Serializing took 336.8392ms. 
BinaryFormatter: Deserializing took 208.7527ms. 

Testing ProtoBuf serializer... 
ProtoBuf: Serializing took 2284.3827ms. 
ProtoBuf: Deserializing took 2201.8072ms. 

Testing NetSerializer serializer... 
NetSerializer: Serializing took 2139.5424ms. 
NetSerializer: Deserializing took 2113.7296ms. 
Press any key to end. 

收集这些结果,我决定去看看的Protobuf或NetSerializer具有较大的物体表现较好。我将收集数量更改为10,000个对象,但将数组大小增加到1-10,000而不是1-100。结果似乎更加明确:

Generating 10000 arrays of data... 
Test data generated. 
Testing BinarySerializer... 
BinaryFormatter: Serializing took 285.8356ms. 
BinaryFormatter: Deserializing took 206.0906ms. 

Testing ProtoBuf serializer... 
ProtoBuf: Serializing took 10693.3848ms. 
ProtoBuf: Deserializing took 5988.5993ms. 

Testing NetSerializer serializer... 
NetSerializer: Serializing took 9017.5785ms. 
NetSerializer: Deserializing took 5978.7203ms. 
Press any key to end. 

我的结论,因此,是:可能存在的protobuf和NetSerializer是非常适合的情况下,但至少相对简单对象的原始性能... BinaryFormatter性能显着提高至少一个数量级。

情况因人而异。

+0

也许BinaryFormatter对数组来说非常快。 – Behrooz 2017-10-28 04:03:55

+2

这是可能的...但提到的情况下,结果是戏剧性的。这里的教训可能就是,不要相信一种方法在任何情况下都是最高性能的。测试和基准测试总是非常有用。 – 2017-10-28 14:29:33

0

我删除了上述代码中的错误,并得到了下面的结果:另外我不确定NetSerializer如何要求您注册正在序列化的类型,可能会产生哪种兼容性或性能差异。

Generating 100000 arrays of data... 
Test data generated. 
Testing BinarySerializer... 
BinaryFormatter: Serializing took 508.9773ms. 
BinaryFormatter: Deserializing took 371.8499ms. 

Testing ProtoBuf serializer... 
ProtoBuf: Serializing took 3280.9185ms. 
ProtoBuf: Deserializing took 3190.7899ms. 

Testing NetSerializer serializer... 
NetSerializer: Serializing took 427.1241ms. 
NetSerializer: Deserializing took 78.954ms. 
Press any key to end. 

修改代码

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.IO; 
using System.Linq; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Text; 
using System.Threading.Tasks; 

namespace SerializationTests 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var count = 100000; 
      var rnd = new Random((int)DateTime.UtcNow.Ticks & 0xFF); 
      Console.WriteLine("Generating {0} arrays of data...", count); 
      var arrays = new List<int[]>(); 
      for (int i = 0; i < count; i++) 
      { 
       var elements = rnd.Next(1, 100); 
       var array = new int[elements]; 
       for (int j = 0; j < elements; j++) 
       { 
        array[j] = rnd.Next(); 
       } 
       arrays.Add(array); 
      } 
      Console.WriteLine("Test data generated."); 
      var stopWatch = new Stopwatch(); 

      Console.WriteLine("Testing BinarySerializer..."); 
      var binarySerializer = new BinarySerializer(); 
      var binarySerialized = new List<byte[]>(); 
      var binaryDeserialized = new List<int[]>(); 

      stopWatch.Reset(); 
      stopWatch.Start(); 
      foreach (var array in arrays) 
      { 
       binarySerialized.Add(binarySerializer.Serialize(array)); 
      } 
      stopWatch.Stop(); 
      Console.WriteLine("BinaryFormatter: Serializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds); 

      stopWatch.Reset(); 
      stopWatch.Start(); 
      foreach (var serialized in binarySerialized) 
      { 
       binaryDeserialized.Add(binarySerializer.Deserialize<int[]>(serialized)); 
      } 
      stopWatch.Stop(); 
      Console.WriteLine("BinaryFormatter: Deserializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds); 


      Console.WriteLine(); 
      Console.WriteLine("Testing ProtoBuf serializer..."); 
      var protobufSerializer = new ProtoBufSerializer(); 
      var protobufSerialized = new List<byte[]>(); 
      var protobufDeserialized = new List<int[]>(); 

      stopWatch.Reset(); 
      stopWatch.Start(); 
      foreach (var array in arrays) 
      { 
       protobufSerialized.Add(protobufSerializer.Serialize(array)); 
      } 
      stopWatch.Stop(); 
      Console.WriteLine("ProtoBuf: Serializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds); 

      stopWatch.Reset(); 
      stopWatch.Start(); 
      foreach (var serialized in protobufSerialized) 
      { 
       protobufDeserialized.Add(protobufSerializer.Deserialize<int[]>(serialized)); 
      } 
      stopWatch.Stop(); 
      Console.WriteLine("ProtoBuf: Deserializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds); 

      Console.WriteLine(); 
      Console.WriteLine("Testing NetSerializer serializer..."); 
      var netSerializerSerialized = new List<byte[]>(); 
      var netSerializerDeserialized = new List<int[]>(); 

      stopWatch.Reset(); 
      stopWatch.Start(); 
      var netSerializerSerializer = new NS(); 
      foreach (var array in arrays) 
      { 
       netSerializerSerialized.Add(netSerializerSerializer.Serialize(array)); 
      } 
      stopWatch.Stop(); 
      Console.WriteLine("NetSerializer: Serializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds); 

      stopWatch.Reset(); 
      stopWatch.Start(); 
      foreach (var serialized in netSerializerSerialized) 
      { 
       netSerializerDeserialized.Add(netSerializerSerializer.Deserialize<int[]>(serialized)); 
      } 
      stopWatch.Stop(); 
      Console.WriteLine("NetSerializer: Deserializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds); 

      Console.WriteLine("Press any key to end."); 
      Console.ReadKey(); 
     } 

     public class BinarySerializer 
     { 
      private static readonly BinaryFormatter Formatter = new BinaryFormatter(); 

      public byte[] Serialize(object toSerialize) 
      { 
       using (var stream = new MemoryStream()) 
       { 
        Formatter.Serialize(stream, toSerialize); 
        return stream.ToArray(); 
       } 
      } 

      public T Deserialize<T>(byte[] serialized) 
      { 
       using (var stream = new MemoryStream(serialized)) 
       { 
        var result = (T)Formatter.Deserialize(stream); 
        return result; 
       } 
      } 
     } 

     public class ProtoBufSerializer 
     { 
      public byte[] Serialize(object toSerialize) 
      { 
       using (var stream = new MemoryStream()) 
       { 
        ProtoBuf.Serializer.Serialize(stream, toSerialize); 
        return stream.ToArray(); 
       } 
      } 

      public T Deserialize<T>(byte[] serialized) 
      { 
       using (var stream = new MemoryStream(serialized)) 
       { 
        var result = ProtoBuf.Serializer.Deserialize<T>(stream); 
        return result; 
       } 
      } 
     } 

     public class NS 
     { 
      NetSerializer.Serializer Serializer = new NetSerializer.Serializer(new Type[] { typeof(int), typeof(int[]) }); 

      public byte[] Serialize(object toSerialize) 
      { 
       using (var stream = new MemoryStream()) 
       { 
        Serializer.Serialize(stream, toSerialize); 
        return stream.ToArray(); 
       } 
      } 

      public T Deserialize<T>(byte[] serialized) 
      { 
       using (var stream = new MemoryStream(serialized)) 
       { 
        Serializer.Deserialize(stream, out var result); 
        return (T)result; 
       } 
      } 
     } 
    } 
}