C# 提高大型';ish';响应

C# 提高大型';ish';响应,c#,performance,wcf,serialization,protobuf-net,C#,Performance,Wcf,Serialization,Protobuf Net,我正在使用Protobuf net实现一个wcf请求/响应服务,用于序列化和tcp绑定。在运行一个测试时,服务器和客户端都在同一台机器上运行,我发现,对于大约1.5Mb的响应对象来说,路由时间大约为500ms 当我将同一对象序列化到内存流时,在客户端接收到响应后,大约需要115ms,而反序列化大约需要330.ms 考虑到从数据库等查询数据的开销,这种方法加上总往返时间 我看到有人写过,这可能是在消息大小的限制,原型缓冲区应该用于,但这是我可以预期的序列化/反序列化时间吗? protobuf ne

我正在使用Protobuf net实现一个wcf请求/响应服务,用于序列化和tcp绑定。在运行一个测试时,服务器和客户端都在同一台机器上运行,我发现,对于大约1.5Mb的响应对象来说,路由时间大约为500ms

当我将同一对象序列化到内存流时,在客户端接收到响应后,大约需要115ms,而反序列化大约需要330.ms
考虑到从数据库等查询数据的开销,这种方法加上总往返时间

我看到有人写过,这可能是在消息大小的限制,原型缓冲区应该用于,但这是我可以预期的序列化/反序列化时间吗? protobuf net是否有任何大小/速度权衡选项? 谢谢

这是目前的模型

public class BaseResponse
{
    public bool Success {get;set;}
    public string Error {get;set;}
}

public class SourceTableResponse : BaseResponse
{
   public Dictionary<string, Dictionary<string,string>> FieldValuesByTableName {get;set;}
}
公共类基类响应
{
公共bool成功{get;set;}
公共字符串错误{get;set;}
}
公共类SourceTableResponse:BaseResponse
{
公共字典字段ValuesByTableName{get;set;}
}

这里有一些技巧可以帮助你,是的。其中最常见的是尽可能多地使用“分组”数据。解释一下:“组”是protobuf规范的一个特性,google不太使用它——他们建议默认使用子对象的长度前缀符号——但长度前缀的编写成本相对较高。在大多数情况下,这就像在一些注释中添加
DataFormat=DataFormat.Group
一样简单,但是:当您有
字典时,这就不那么简单了-因为
KeyValuePair
受protobuf-net保护,以防止善意的用户破坏它:它不允许您更改格式。我们仍然可以这样做,但是:我们需要编写自己的模型,而不是使用裸字典——这有点痛苦

其他窍门:

  • 在原语列表上使用“压缩”编码——这里不适用;你没有
  • 利用interning来处理大量重复的字符串值——看看您的模型,我猜内部字典的键是一个字段名,因此可能会在表之间重复使用很多次;我们可以试着再实习一次,但如果是
    字典
    ,我们就无能为力了
但在一个基本层面上:您的数据目前将被UTF-8控制,无论是在存储还是处理方面。我对此无能为力,因为您将所有内容都存储为字符串。就我个人而言,我会说这个非常松散的模型实际上并不适合充分利用protobuf网络;我所能做的就是把它拧紧到极限范围内。例如,这仅适用于转发(无缓冲):

但如果这不可能,那么我想您仍然可以避免在数据中出现200次
“DateOfBirth”

[ProtoMember(1, AsReference=true)]
public string Name { get; set; }
[ProtoMember(2)]
public string Value { get; set; }
但请注意:这比使用类型化模型要昂贵得多,原因有多种:

  • 所有这些文字都很昂贵
  • 需要存储名称(protobuf的一部分优点是它完全避免了存储名称)
  • 所有这些文字都是昂贵的(是的,我已经说过了——但它真的很重要)

    • 这里有一些技巧可以帮助你,是的。其中最常见的是尽可能多地使用“分组”数据。解释一下:“组”是protobuf规范的一个特性,google不太使用它——他们建议默认使用子对象的长度前缀符号——但长度前缀的编写成本相对较高。在大多数情况下,这就像在一些注释中添加
      DataFormat=DataFormat.Group
      一样简单,但是:当您有
      字典时,这就不那么简单了-因为
      KeyValuePair
      受protobuf-net保护,以防止善意的用户破坏它:它不允许您更改格式。我们仍然可以这样做,但是:我们需要编写自己的模型,而不是使用裸字典——这有点痛苦

      其他窍门:

      • 在原语列表上使用“压缩”编码——这里不适用;你没有
      • 利用interning来处理大量重复的字符串值——看看您的模型,我猜内部字典的键是一个字段名,因此可能会在表之间重复使用很多次;我们可以试着再实习一次,但如果是
        字典
        ,我们就无能为力了
      但在一个基本层面上:您的数据目前将被UTF-8控制,无论是在存储还是处理方面。我对此无能为力,因为您将所有内容都存储为字符串。就我个人而言,我会说这个非常松散的模型实际上并不适合充分利用protobuf网络;我所能做的就是把它拧紧到极限范围内。例如,这仅适用于转发(无缓冲):

      但如果这不可能,那么我想您仍然可以避免在数据中出现200次
      “DateOfBirth”

      [ProtoMember(1, AsReference=true)]
      public string Name { get; set; }
      [ProtoMember(2)]
      public string Value { get; set; }
      
      但请注意:这比使用类型化模型要昂贵得多,原因有多种:

      • 所有这些文字都很昂贵
      • 需要存储名称(protobuf的一部分优点是它完全避免了存储名称)
      • 所有这些文字都是昂贵的(是的,我已经说过了——但它真的很重要)

      您的对象模型是什么样子的?是的,有一些技巧可以最小化瓶颈,特别是在子对象(单个或列表)和基本体的列表/数组周围。你有我可以攻击的例子吗?谢谢Marc,我用一个例子更新了这个问题,这个模型是什么样的,它仍然在进行中。什么是
      列表
      ?还有:这就是整个模型吗?i、 大部分数据都是非结构化字符串吗?对不起,这应该是一个dict
      [ProtoMember(1, AsReference=true)]
      public string Name { get; set; }
      [ProtoMember(2)]
      public string Value { get; set; }