【问题标题】:c# improve binary serializationc# 改进二进制序列化
【发布时间】:2016-07-27 22:49:15
【问题描述】:

我目前正在从事一个基于其他代码生成代码的项目。本质上将编程语言本身用作 DSL。

生成器目标之一是 binary DataContract serializer 和为以下类生成的 ToBytes

[DataContract]
public partial class Root
{
    [DataMember]
    public int Number { get; set; }

    [DataMember]
    public Partial[] Partials { get; set; }

    [DataMember]
    public IList<ulong> Numbers { get; set; }
}

变成这样:

public int Size
{
    get 
    { 
        var size = 8;
        // Add size for collections and strings
        size += Partials.Sum(entry => entry.Size);
        size += Numbers.Count * 8;

        return size;              
    }
}
public byte[] ToBytes()
{
    var index = 0;
    var bytes = new byte[Size];

    return ToBytes(bytes, ref index);
}
public byte[] ToBytes(byte[] bytes, ref int index)
{
    // Convert Number
    Buffer.BlockCopy(BitConverter.GetBytes(Number), 0, bytes, index, 4);;
    index += 4;
    // Convert Partials
    // Two bytes length information for each dimension
    Buffer.BlockCopy(BitConverter.GetBytes((ushort)(Partials == null ? 0 : Partials.Length)), 0, bytes, index, 2);
    index += 2;
    foreach(var value in Partials ?? Enumerable.Empty<Partial>())
    {
        value.ToBytes(bytes, ref index);
    }
    // Convert Numbers
    // Two bytes length information for each dimension
    Buffer.BlockCopy(BitConverter.GetBytes((ushort)(Numbers == null ? 0 : Numbers.Count)), 0, bytes, index, 2);
    index += 2;
    foreach(var value in Numbers ?? Enumerable.Empty<ulong>())
    {
        Buffer.BlockCopy(BitConverter.GetBytes(value), 0, bytes, index, 8);;
        index += 8;
    }
    return bytes;
}

现在即使很难,这真的很快,我正在寻找一种方法来加速 Buffer.BlockCopy(BitConverter.GetBytes 的所有使用。为每次转换创建一个新的小byte[] 然后在我已经拥有byte[] 和位置时复制它似乎仍然是浪费资源。

有什么想法可以最好地改进代码吗?

更新:基于@adrianm 评论,我将用for 循环替换foreach 数组,并在if 语句中包装可空类型。不希望使用 another thread 中的结构。我宁愿使用类和 [DataContract] 属性。另外为了符合 Linux 规范,我不能使用 WinApi。

Update2:添加了生成的其余代码。感谢评论未来的版本将包括

if (index + Size > bytes.Length)
    // Some error handling

【问题讨论】:

  • 分配和字节复制真的很快。我的猜测是,如果您专注于代码中的其他部分,例如使用 for loops 而不是 foreachif 而不是 ?? Enumerable.Empty,您可以提高速度。
  • 通常是structMarshal.StructureToPtr,如果你需要fast,那么winapi方法是the way去。
  • @adrianm 好点。我使用了foreach,因为它与所有集合兼容,但查看ArrayEnumerator,这可能是一个令人费解的选择。感谢您的反馈。
  • @Sinatr 老实说我不知道​​这一点,但似乎它不能完全涵盖我想做的事情。同样使用结构意味着每次分配到某个地方时都会复制它。如果一个大的实例得到了很多传递,这将是一个性能损失,不是吗?并且在 Linux/Mono 上使用 WinApi 将无法正常工作,对吗?
  • BitConverter 并不神奇。 MyBitConverter.GetBytes(int, byte[] buffer, int offset) 写起来很简单。相关:stackoverflow.com/questions/2527018

标签: c# binary unsafe bitconverter


【解决方案1】:

所以我看到了BitConverter 的实现以及它们使用不安全和指针来创建byte[]。我想在生成的代码中使用它:

*byte pointer = bytes;
*((int*)pointer + pos) = Number;
pos += 4;

但在这种情况下,这将是一个不安全的方法,我不确定这会对那里的托管代码产生什么影响。

【讨论】:

  • 使用unsafe 方法对其余托管代码没有任何作用。 unsafe != unmanaged
猜你喜欢
  • 2017-10-18
  • 1970-01-01
  • 2010-12-17
  • 2015-09-17
  • 2016-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
相关资源
最近更新 更多