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



답변

다음은 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);
        }
    }
}


답변


답변

이것에 관심이있어서 나는 내가 할 수있는 가장 가까운 “사과 대 사과”테스트로 제안 된 방법을 테스트하기로 결정했습니다. 다음 코드로 콘솔 앱을 작성했습니다.

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-100 개가 아닌 1-10,000 개로 늘 렸습니다. 결과는 훨씬 더 명확 해 보였습니다.

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는 적어도 10 배 이상 성능이 훨씬 뛰어납니다.

YMMV.


답변

Protobuf는 매우 빠릅니다.

이 시스템의 성능 및 구현에 대한 자세한 정보는 http://code.google.com/p/protobuf-net/wiki/Performance 를 참조 하십시오 .


답변

초고속이라고 주장하는 또 다른 직렬 변환기는 netserializer 입니다.

그들의 사이트에 제공된 데이터는 protobuf보다 2x-4x의 성능을 보여줍니다 . 나는 이것을 직접 시도하지 않았지만 다양한 옵션을 평가하고 있다면 이것을 시도하십시오.


답변

.net에 포함 된 이진 직렬 변환기는 XmlSerializer보다 빠릅니다. 또는 protobuf, json, …

그러나 일부의 경우 속성을 추가하거나 메타 데이터를 추가하는 다른 방법이 필요합니다. 예를 들어 ProtoBuf는 내부적으로 숫자 속성 ID를 사용하며 매핑은 다른 메커니즘에 의해 어떻게 든 보존되어야합니다. 버전 관리는 serializer에서 사소한 일이 아닙니다.


답변

위 코드에서 버그를 제거하고 결과는 다음과 같습니다. 또한 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;
                }
            }
        }
    }
}