【问题标题】:Performance of protobuf-net vs DataContractSerializer over WCFprotobuf-net 与 DataContractSerializer 在 WCF 上的性能
【发布时间】:2011-04-26 08:34:22
【问题描述】:

我测试了 protobuf 序列化,似乎对于低于一定数量的对象,它比常规的 datacontract 序列化慢。使用 DataContractSerializer 传输大小更大,但在序列化和反序列化过程中使用 DataContractSerializer 更快

你认为这是正常的还是我弄错了?

[DataContract]
public partial class Toto
{
    [DataMember]
    public string NomToto { get; set; }

    [DataMember]
    public string PrenomToto { get; set; }
} 

这是我的数据合同类,这与 protobuf 相同

[ProtoContract]
public partial class Titi
{
    [ProtoMember(1)]
    public string NomTiti { get; set; }

    [ProtoMember(2)]
    public string PrenomTiti { get; set; }
}

这是我使用 protobuf 进行 WCF 服务的方法(对于没有 ms 的数据合同也是如此)

public class TitiService : ITitiService
{
    public byte[] GetAllTitis()
    {
        List<Titi> titiList = new List<Titi>();
        for (int i = 0; i < 20000; i++)
        {
            var titi = new Titi
            {
                NomTiti = "NomTiti" + i,
                PrenomTiti = "PrenomTiti" + i
            };
            titiList.Add(titi);
        }
        var ms = new MemoryStream();
        Serializer.Serialize(ms, titiList);

        byte[] arr = ms.ToArray();
        return arr;
    }
}

带有数据契约的服务

public class TotoService : ITotoService
{
    public List<Toto> GetAllTotos()
    {
        List<Toto> totoList = new List<Toto>();
        for (int i = 0; i<20000; i++)
        {
            var toto = new Toto
            {
                NomToto = "NomToto" + i,
                PrenomToto = "PrenomToto" + i
            };
            totoList.Add(toto);
        }
        return totoList;
    }
}

这里是客户端调用

    public partial class Program
{
    static ProtobufTestAzure.Client.TitiService.TitiServiceClient TitiClient;
    static ProtobufTestAzure.Client.TotoService.TotoServiceClient TotoClient;

    public static void Main(string[] args)
    {
        Stopwatch stopwatch1 = new Stopwatch();
        Stopwatch stopwatch2 = new Stopwatch();
        Stopwatch stopwatch3 = new Stopwatch();

        stopwatch1.Start();

        TitiClient = new ProtobufTestAzure.Client.TitiService.TitiServiceClient();
        Byte[] titiByte = TitiClient.GetAllTitis();
        TitiClient.Close();

        stopwatch1.Stop();


        stopwatch2.Start();

        var ms = new MemoryStream(titiByte);
        List<Titi> TitiList = Serializer.Deserialize<List<Titi>>(ms);

        stopwatch2.Stop();

        Console.WriteLine(" ");

        stopwatch3.Start();

        TotoClient = new ProtobufTestAzure.Client.TotoService.TotoServiceClient();
        var TotoList = TotoClient.GetAllTotos();
        TotoClient.Close();

        stopwatch3.Stop();

        Console.WriteLine("Time elapse for reception (Protobuf): {0} ms ({1} éléments)", stopwatch1.ElapsedMilliseconds, TitiList.Count);
        Console.WriteLine("Time elapse for deserialization (Protobuf : {0} ms ({1} éléments)", stopwatch2.ElapsedMilliseconds, TitiList.Count);
        Console.WriteLine("Time elapse for réception (Datacontract Serialization) : {0} ms ({1} éléments)", stopwatch3.ElapsedMilliseconds, TotoList.Count);

        Console.ReadLine();
    }
}

以及 10000 个对象的结果

接收时间 (Protobuf):3359 毫秒(10000 个元素) 反序列化所用时间 (Protobuf):138 毫秒(10000 个元素) 接收时间流逝(Datacontract序列化):2200ms(10000个元素)

我用 20000 个对象对其进行了测试 它给了我第一个电话

接收时间(Protobuf):11258ms(20000 个元素) 反序列化所用时间(Protobuf):133ms(20000 个元素) 接收时间(Datacontract序列化):3726ms(20000个元素)

第二次通话

接收时间 (Protobuf):2844 毫秒(20000 个元素) 反序列化所用时间 (Protobuf):141 毫秒(20000 个元素) 接收时间流逝(Datacontract 序列化):7541 毫秒(20000 个元素)

第三个

接收时间(Protobuf):2767ms(20000 个元素) 反序列化所用时间 (Protobuf):145 毫秒(20000 个元素) 接收时间流逝(Datacontract 序列化):3989 毫秒(20000 个元素)

在“Protobuf transfert”上激活 MTOM 后,它给了我:

第一次通话

接收时间 (Protobuf):3316 毫秒(20000 个元素) 反序列化所用时间(Protobuf):63 ms(20000 个元素) 接收时间流逝(Datacontract 序列化):3769 毫秒(20000 个元素)

第二次通话

接收时间 (Protobuf):2279 毫秒(20000 个元素) 反序列化所用时间(Protobuf):57 毫秒(20000 个元素) 接收时间流逝(Datacontract 序列化):3959 毫秒(20000 个元素)

我为对象大小添加了这部分代码

            long totoSize = new long();
        using (Stream s = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(s, totoList);
            totoSize = s.Length;
        }

        long titiSize = titiByte.Count();

它给了我 637780 和 protobuf 和 1038236 和 DataContractSerializer 今天早上的通话时间更好,更稳定 第一次通话 protobuf = 2498 毫秒 数据合约 = 5085 毫秒

第二次通话 protobuf = 3649 毫秒 数据合约 = 3840 毫秒

第三次调用 protobuf = 2498 毫秒 数据合约 = 5085 毫秒

【问题讨论】:

  • 你怎么能指望有人告诉你如果你犯了一个错误而不显示你实际做了什么,例如显示你测试过的代码(它的两个版本)?
  • 能否发布您的方法和代码(如果存在)进行测试?
  • 顺便说一句,常规 XML 序列化!= datacontract 序列化;两者是相关的,但非常不同。但我赞同上述观点;没有更多的上下文,这是不可能评论的。
  • 对不起,XML序列化和Datacontract序列化的错误,我使用最后一个,我用我的代码编辑
  • @Marc 我用 WireShark 对其进行了测试,它给了我大约 700 Ko 的 protobuf 和 2Mo 的 dataContractSerializer,你做得真好

标签: c# datacontractserializer protobuf-net


【解决方案1】:

影响性能的一些因素:

  • 序列化器准备好了吗?这在每种类型的第一次使用时是自动的;第一次通过,它需要做很多检查等来弄清楚你的模型是如何工作的。您可以通过在启动期间的某处调用Serializer.PrepareSerializer&lt;YourType&gt;() 来抵消这一点
    • 或者作为替代方案,在 v2(以“alpha”形式提供)中,如果您需要尽可能快的冷启动性能,您可以将序列化程序预生成为 dll
  • 什么是传输?特别是对于 WCF,您需要记住您的 byte[] 是如何编码的(当然,这在套接字上不是问题);例如,传输可以使用 MTOM 吗?或者是base-64编码byte[]
    • 还要注意Streambyte[] 的处理方式可能不同;如果你可以测量带宽,你可能想同时尝试
    • 如果绝对速度是您的目标,那么启用 MTOM 的基本 http 是我对 WCF 传输的偏好;或套接字,如果你想更接近极限

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-20
    • 1970-01-01
    • 2014-12-18
    • 1970-01-01
    • 1970-01-01
    • 2016-11-05
    • 2018-06-29
    • 2020-11-16
    相关资源
    最近更新 更多