所以我最近一直在System.Buffers
和ReadOnlySequence<T>
班级一起工作。
我有一个用以下定义的原语结构:
[StructLayout(LayoutKind.Sequential,Pack =1,CharSet=CharSet.Unicode)]
public partial struct MessageHeader
{
public MessageVersion Version;
...
我可以毫无问题地在网络上来回传递它,我正在利用System.IO.Pipelines
这一点。
将ReadOnlySequence<byte>
背部转换为结构引起了一些头痛。
我从这个开始:
private void ExtractMessageHeaderOld(ReadOnlySequence<byte> ros, out MessageHeader messageHeader)
{
var x = ros.ToArray<byte>();
ReadOnlySpan<MessageHeader> mhSpan = MemoryMarshal.Cast<byte, MessageHeader>(x);
messageHeader = mhSpan[0];
}
它在服务器的整个生命周期中创建了数千个小字节 [] 数组(这本身没有问题),但是系统尝试执行的所有其他操作都给 GC 带来了一些额外的压力。
所以我已经开始使用:
private void ExtractMessageHeader(ReadOnlySequence<byte> ros, out MessageHeader messageHeader, ref byte[] workingSpace)
{
var i = 0;
foreach (var rom in ros)
foreach (var b in rom.Span)
{
workingSpace[i] = b;
i++;
}
ReadOnlySpan<MessageHeader> mhSpan = MemoryMarshal.Cast<byte, MessageHeader>(workingSpace);
messageHeader = mhSpan[0];
}
这不会做任何内存分配,但我只是觉得应该有更好的方法。
foreach
循环和to MemoryMarshal.Cast()
amessageHeader[1]
这样我就可以提取元素 0 有点像我在阅读源代码时偶然发现的黑客行为。
我找不到一个 API 来干净地将内容提取ReadOnlySequence<bytes>
到messageHeader
.
编辑1:
我只是偶然发现BuffersExtensions.CopyTo<T>(ReadOnlySequence<T>, Span<T>)
可以用它替换 foreach 循环。
ros.CopyTo(workingSpace);