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

时间:2018-08-10 18:52:55

标签: c# sockets .net-core

在Marc Gravell的blog post主题中对管道进行了精彩的介绍之后,我正在修补实现带有套接字的管道。

我知道Marc已经提出Pipelines.Sockets.Unofficial ,我将其用作参考,但是我有一个问题。

似乎SocketAsyncEventArgsSetBuffer()方法有新的重载:SetBuffer(Memory<byte>)

似乎这里的目的是与Pipes很好地集成。

我的困惑是由于Pipe.Reader.ReadAsync()返回包含ReadResultReadOnlySequence<byte>)的ReadResult.Buffer

Buffer.IsSingleSegment == true的情况下,很明显该怎么做:

SocketAsyncEventArgs.SetBuffer(Buffer[0])

但是在有多个细分的情况下,我不能完全确定最佳做法是什么。

我当然可以从管道中获取一个byte[]并完成它,但这会产生一个副本(甚至可能有多个副本)。

此处ReadOnlySequence<byte>的用途是什么?有没有办法获取表示序列全部内容的“内存”?

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

1 个答案:

答案 0 :(得分:1)

对于我所看到的: 有这个ReadOnlySequence<>.First,在IsSingleSegment的情况下,应该会为您提供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<>中的这种“顺序”内存访问模式。