最快速的序列化和反序列化.NET对象的方法

aro*_*ron 82 .net c# serialization deserialization

我正在寻找最快的序列化和反序列化.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);
    }        
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 53

这是你的模型(发明的CTTE使用protobuf-net)(但保留了使用的能力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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @BjarkeCK 我强烈不同意;对于大多数人来说,这甚至“远程”都没有用。接下来做什么——每天写我们自己的收藏?不:即使做得相当好也是*困难*的。当然,如果您确实需要最快的输出:您将不得不亲自动手 - 但对于大多数人来说,这样做会“非常”浪费他们的时间。**充其量**他们会花费更长的时间。更有可能的是,他们的代码存在缺陷、不可靠,并且可能比使用可用的库慢。大多数人应该专注于*他们的应用程序需要什么*,而不是这些细节。 (5认同)
  • G'day Marc,热爱您完成的协议缓冲区工作,我知道这篇文章已经有5年的历史了,但此处答案(Binoj)中引用的netserializer具有衡量指标,表明您的实现不是最快的。这是一个公正的声明/广告,还是需要权衡取舍?谢谢 (2认同)
  • @BjarkeCK 序列化器本质上涉及更多一些,因为它们需要做很多事情来防止人们自行其是(尤其是当他们迭代版本时);大多数人不想花一生的时间来调试序列化代码,因此:一个好的序列化器 - 虽然无疑比完美实现的版本不容忍的手动实现慢 - 对于大多数人来说通常是一个很好的折衷方案 (2认同)

Max*_*xim 28

我在这篇文章中对差异格式进行了全面的比较 - http://maxondev.com/serialization-performance-comparison-c-net-formats-frameworks-xmldatacontractserializer-xmlserializer-binaryformatter-json-newtonsoft-servicestack-text/

只有一个样本来自后 在此输入图像描述

  • 那不是速度.那很慢.它在文章链接中说"越小越好". (2认同)
  • @TimurNuriyasov,这是做手术的时间 (2认同)
  • 所以你说二进制是最慢的?我不这么认为!我猜它正确指的是速度,而不是时间. (2认同)
  • 二进制是最慢的。试试看 但我会说这是最简单的,因为它不需要任何自定义解析内容即可正确处理多态对象(接口等) (2认同)
  • @Kamarey 看看我下面的测试...二进制文件比其他文件快*方式*。 (2认同)

Pie*_*kel 14

Protobuf非常快.

有关此系统性能和实施的详细信息,请参阅http://code.google.com/p/protobuf-net/wiki/Performance.

  • 你必须注释你的对象.Protobuf不像序列化程序那样存储字段名称和类型,而是从实际类型中获取它们.这是目标文件小得多的原因之一.文档解释了所有这些.我已经使用它一段时间了,如果你需要快速(反)序列化和小目标文件,protobuf真的是要走的路. (9认同)

Jer*_*acs 14

对此感兴趣,我决定用最接近的"苹果到苹果"测试来测试建议的方法.我写了一个Console应用程序,其代码如下:

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

结果让我感到惊讶; 多次运行时它们是一致的:

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.
Run Code Online (Sandbox Code Playgroud)

收集这些结果后,我决定看看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.
Run Code Online (Sandbox Code Playgroud)

因此,我的结论是:可能存在ProtoBuf和NetSerializer非常适合的情况,但就至少相对简单的对象的原始性能而言...... BinaryFormatter的性能要高出至少一个数量级.

因人而异.

  • @JeremyHolovacs:如果是这样,那么我应该很高兴我的序列化器是组中[最快的序列化器](https://dotnetfiddle.net/K80nIm)。尽管如此,我还是会更仔细地制定。这是一个 11 年前的问题,当时多态序列化器的安全缺陷并没有受到如此重视。我[在此答案中]收集了一些具体的安全问题(/sf/answers/4697530911/)。我专注于“BinaryFormatter”,但许多问题也会影响其他序列化器。 (3认同)
  • 这是可能的......但在上述条件下,结果是戏剧性的.这里的教训可能就是,不要相信一种方法在所有情况下都是最高效的.测试和基准测试总是很有启发性. (2认同)

Bin*_*ony 13

另一个声称超快的串行器netserializer.

他们网站上提供的数据显示比protobuf高2倍,我自己没有尝试过,但如果你正在评估各种选项,那么试试这个

  • 我刚刚在我的应用程序中尝试了NetSerializer,它可以创造奇迹.值得一试. (3认同)

Cod*_*aos 6

.net 中包含的二进制序列化程序应该比 XmlSerializer 更快。或者另一个用于 protobuf、json、...的序列化程序

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