简体   繁体   English

将字节写入结构中的字节数组的最佳方法?

[英]Best way to write bytes to a byte array in a struct?

I'm trying to create a packet struct that is basically a byte builder of fixed length.我正在尝试创建一个数据包结构,它基本上是一个固定长度的字节生成器。 I have a WriteByte function written in 3 different ways.我有一个用 3 种不同方式编写的 WriteByte function。 Just wondering which is best (or if there's a better way altogether) and which will keep the GC happy.只是想知道哪个是最好的(或者是否有更好的方法)以及哪个会让 GC 满意。 BTW, I have a Position field that has to be updated when a byte(s) is written.顺便说一句,我有一个 Position 字段,在写入一个字节时必须对其进行更新。 The functions will expand to include WriteUInt16, WriteFloat etc... Not sure what the best approach is.这些功能将扩展到包括 WriteUInt16、WriteFloat 等...不确定最佳方法是什么。 Any advice is appreciated.任何建议表示赞赏。

  1. Should this be a struct?这应该是一个结构吗? I'd like to do as little allocation as possible because these Packs will be created very frequently.我想做尽可能少的分配,因为这些包会非常频繁地创建。
  2. Should I put the WriteByte in the struct itself as a method (option 1), as an extension of Pack (passed by ref) (option 2), or just use a static helper class (passed by ref) (option 3)?我应该将 WriteByte 作为方法(选项 1),作为 Pack 的扩展(由 ref 传递)(选项 2),还是只使用 static 助手 class(由 ref 传递)(选项 3)?

Here's the code:这是代码:

public struct Pack
{
    public byte[] Data { get; internal set; }
    public int Pos { get; internal set; }
    
    public Pack(byte opcode, ushort size)
    {
        ++size;                     // make room for byte opcode
        Data = new byte[2 + size];  // make room to prepend the size (ushort)
        BitConverter.GetBytes(size).CopyTo(Data, 0);
        Data[2] = opcode;
        Pos = 3;                    // start writing at position 3
    }

    // option 1
    // use: pack.WriteByte(0x01)
    public void WriteByte(byte value) => Data[Pos++] = value;
}

public static class SPackExtensions
{
    // option 2
    // use: pack.WriteByte(0x01)
    public static void WriteByte(ref this Pack pack, byte value)
    {
        pack.Data[pack.Pos++] = value;
    }
}

public static class PackWriter
{
    // option 3
    // use: PackWriter.WriteByte(ref pack, 0x01)
    public static void WriteByte(ref Pack pack, byte value)
    {
        pack.Data[pack.Pos++] = value;
    }
}

Should this be a struct?这应该是一个结构吗? I'd like to do as little allocation as possible because these Packs will be created very frequently.我想做尽可能少的分配,因为这些包会非常频繁地创建。

Maybe.或许。 Even with a struct you will still be allocating two objects, one when converting the size to an array, and one for the array itself.即使使用结构,您仍将分配两个对象,一个用于将大小转换为数组,另一个用于数组本身。 So the overhead for allocating the object will probably be negligible, especially since it will probably be much smaller than the array.因此分配 object 的开销可能可以忽略不计,特别是因为它可能比数组小得多。 However, structs are recommended to be immutable , since it can be quite confusing when passing around a object if the data-array is shared, but the Pos is not.但是, 建议结构是不可变的,因为如果共享数据数组但 Pos 不是,则在传递 object 时可能会非常混乱。

But you should probably use BitConverter.TryWriteBytes or BinaryPrimitives.TryWriteInt16LittleEndian to avoid the allocation when writing the length.但是您可能应该使用BitConverter.TryWriteBytesBinaryPrimitives.TryWriteInt16LittleEndian来避免在写入长度时进行分配。

Should I put the WriteByte in the struct itself as a method (option 1), as an extension of Pack (passed by ref) (option 2), or just use a static helper class (passed by ref) (option 3)?我应该将 WriteByte 作为方法(选项 1),作为 Pack 的扩展(由 ref 传递)(选项 2),还是只使用 static 助手 class(由 ref 传递)(选项 3)?

The generated code should be identical, so go for whatever is easiest to use and most readable.生成的代码应该是相同的,所以 go 是最容易使用和最易读的代码。 I would probably argue for option 1. In my opinion, using extension methods or helper classes would bring little advantages in this case.我可能会赞成选项 1。在我看来,在这种情况下使用扩展方法或辅助类几乎没有什么优势。

these Packs will be created very frequently这些包将非常频繁地创建

When writing performance optimized code, a good principle is avoiding allocations altogether.在编写性能优化代码时,一个好的原则是完全避免分配。 And as far as I can see this object would be impossible to put into a object pool and reuse, since the position parameter is not possible to reset.据我所知,这个 object 不可能放入 object 池中并重复使用,因为 position 参数无法重置。 So I would consider basing my object around a span that is fetched from a pool of fixed size buffers.因此,我会考虑将我的 object 基于从固定大小缓冲区池中获取的跨度。

Also, I would highly recommend that you profile your code.另外,我强烈建议您分析您的代码。 "Very frequently" might range from a 1hz to 10^9hz depending on context. “非常频繁”的范围可能从 1hz 到 10^9hz,具体取决于上下文。 So you should check if this is an actual problem in your particular context.因此,您应该检查在您的特定上下文中这是否是一个实际问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM