提问人:Chroma 提问时间:3/11/2022 最后编辑:Chroma 更新时间:3/11/2022 访问量:731
将字节写入结构中的字节数组的最佳方法?
Best way to write bytes to a byte array in a struct?
问:
我正在尝试创建一个数据包结构,它基本上是固定长度的字节构建器。我有一个以 3 种不同方式编写的 WriteByte 函数。只是想知道哪个是最好的(或者是否有更好的方法),哪个会让 GC 满意。顺便说一句,我有一个位置字段,在写入字节时必须更新。这些函数将扩展为包括 WriteUInt16、WriteFloat 等...不确定最好的方法是什么。任何建议都是值得赞赏的。
- 这应该是一个结构体吗?我想尽可能少地进行分配,因为这些包将非常频繁地创建。
- 我应该将 WriteByte 作为方法(选项 1)、作为 Pack 的扩展(由 ref 传递)(选项 2)还是只使用静态帮助程序类(由 ref 传递)(选项 3)?
代码如下:
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;
}
}
答:
这应该是一个结构体吗?我想尽可能少地进行分配,因为这些包将非常频繁地创建。
或。即使使用结构,您仍将分配两个对象,一个在将大小转换为数组时,另一个用于数组本身。因此,分配对象的开销可能可以忽略不计,特别是因为它可能比数组小得多。但是,建议结构是不可变的,因为如果共享数据数组,但 Pos 不是,则在传递对象时可能会非常混乱。
但是,在编写长度时,您可能应该使用或避免分配。BitConverter.TryWriteBytes
BinaryPrimitives.TryWriteInt16LittleEndian
我应该将 WriteByte 作为方法(选项 1)、作为 Pack 的扩展(由 ref 传递)(选项 2)还是只使用静态帮助程序类(由 ref 传递)(选项 3)?
生成的代码应该是相同的,因此请选择最容易使用且最易读的代码。我可能会支持选项 1。在我看来,在这种情况下,使用扩展方法或帮助程序类不会带来什么好处。
这些包将非常频繁地创建
在编写性能优化代码时,一个好的原则是完全避免分配。据我所知,这个对象不可能放入对象池中并重用,因为位置参数无法重置。因此,我会考虑将我的对象基于从固定大小缓冲区池中获取的跨度。
另外,我强烈建议您分析您的代码。“非常频繁”的范围可能从 1hz 到 10^9hz 不等,具体取决于上下文。因此,您应该检查这是否是您的特定上下文中的实际问题。
上一个:更改结构中元素的值
下一个:结构指针的单指针或双指针
评论
System.IO.Pipelines
。基于堆的数组,效率明显较低。ref struct
Span
BinaryPrimitives
BitConverter
BinaryPrimitives
BitConverter