从 ReadOnlySequence<byte> 中获取连续的 Memory<byte>

9
在Marc Gravell关于管道的博客文章中对管道进行了精彩的介绍后,我正在尝试使用套接字实现管道。
我知道Marc已经提出了Pipelines.Sockets.Unofficial,我正在使用它作为参考,但我有一个问题。
似乎SocketAsyncEventArgsSetBuffer()方法有一个新的重载:SetBuffer(Memory<byte>) 这里的意图似乎是与管道很好地集成。
我的困惑来自于Pipe.Reader.ReadAsync()返回一个包含ReadOnlySequence<byte>ReadResult.Buffer)的ReadResult
如果Buffer.IsSingleSegment == true,那么该怎么做就很明显了:

SocketAsyncEventArgs.SetBuffer(Buffer[0])

但是在存在多个段的情况下,我不确定最佳操作方式是什么。

当然,我可以从管道中获取一个byte[]并完成操作,但这会产生一次复制(甚至可能不止一次)。

这里ReadOnlySequence<byte>的预期用途是什么?有没有一种方法可以获取表示序列整个内容的“Memory”?

也许我需要重新阅读Marc的博客文章...


2
ReadOnlySequence没有索引器。 - pamidur
1个回答

4
我所看到的是: 如果 IsSingleSegment 为真,那么这个 ReadOnlySequence<>.First 应该会给你想要的 ReadOnlyMemory<>。 对于有多个段的序列,我认为你应该使用迭代来遍历它们。
var iSegment = seq.Start;
ReadOnlyMemory<byte> readMemory;
while(seq.TryGet(ref iSegment, out readMemory, advance: true))
{ /* do smth */ }

另外我认为,以下方法也能达到同样的效果:

foreach(var memory in seq)
{ /* do smth */ }

如果你在意性能并且不想复制整个缓冲区(这就是.ToArray()扩展方法的作用),那么迭代遍历是有意义的。我认为,意图是有效地表示非连续缓冲区。我对Sequence<>实现细节不确定,但在大多数缓冲区方案中,保持几个小缓冲区(3、2)并在它们之间切换以避免不必要地分配新内存是很常见的。有时会将其抽象为"循环"或"环形"缓冲区。这导致了像Sequence<>中的"顺序"内存访问模式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接