我正在开发的应用程序非常注重性能,因此需要将分配保持在最低水平以保持GC停滞。
我很惊讶地发现System.Guid
没有公开任何方法将它的byte[]
表示复制到现有缓冲区中。唯一的现有方法Guid.ToByteArray()
执行new byte[]
分配,否则没有它就无法获得基础字节。
所以我正在寻找的是将Guid
复制到已存在的byte[]
缓冲区而不分配任何内存的方法(因为Guid
已经是值类型)。
答案 0 :(得分:3)
我确定的解决方案来自Jil project Kevin Montrose的一些帮助。我没有采用那种确切的解决方案,但它激发了我想出一些我认为相当优雅的东西。
注意:以下代码使用Fixed Size Buffers,并要求使用/unsafe
开关构建项目(并且很可能需要运行Full Trust)。
[StructLayout(LayoutKind.Explicit)]
unsafe struct GuidBuffer
{
[FieldOffset(0)]
fixed long buffer[2];
[FieldOffset(0)]
public Guid Guid;
public GuidBuffer(Guid guid)
: this()
{
Guid = guid;
}
public void CopyTo(byte[] dest, int offset)
{
if (dest.Length - offset < 16)
throw new ArgumentException("Destination buffer is too small");
fixed (byte* bDestRoot = dest)
fixed (long* bSrc = buffer)
{
byte* bDestOffset = bDestRoot + offset;
long* bDest = (long*)bDestOffset;
bDest[0] = bSrc[0];
bDest[1] = bSrc[1];
}
}
}
用法很简单:
var myGuid = Guid.NewGuid(); // however you get it
var guidBuffer = new GuidBuffer(myGuid);
var buffer = new buffer[16];
guidBuffer.CopyTo(buffer, 0);
这个时间产生了副本的平均持续时间1-2 ticks 。对于大多数应用来说应该足够快。
但是,如果你想要实现绝对的最佳性能,一种可能性(凯文建议)是确保offset
参数为long
- 对齐(在8字节边界上)。我的特定用例有利于内存超速,但如果速度是最重要的,那将是一个很好的方法。
答案 1 :(得分:1)
如果速度是主要考虑因素,则可以直接使用Guid
而不是通过GuidBuffer
结构来节省大量时间。这是我正在使用的扩展方法。
public static unsafe void Encode(this byte[] array, int offset, Guid value)
{
if (array.Length - offset < 16) new ArgumentException("buffer too small");
fixed (byte* pArray = array)
{
var pGuid = (long*)&value;
var pDest = (long*)(pArray + offset);
pDest[0] = pGuid[0];
pDest[1] = pGuid[1];
}
}
用法:
var guid = Guid.NewGuid();
var array = new byte[16];
array.Encode(0, guid);