C#7.2引入了两种新类型:Span<T>
和Memory<T>
具有比诸如C的早期C#类型更好的性能string[]
。
问题:Span<T>
和之间有什么区别Memory<T>
?为什么我要一个使用另一个?
C#7.2引入了两种新类型:Span<T>
和Memory<T>
具有比诸如C的早期C#类型更好的性能string[]
。
问题:Span<T>
和之间有什么区别Memory<T>
?为什么我要一个使用另一个?
Answers:
Span<T>
本质上是仅堆栈的,而Memory<T>
可以存在于堆中。
Span<T>
是一种新类型,我们要添加到平台中以表示任意内存的连续区域,其性能特征与T []相同。它的API与数组相似,但是与数组不同,它可以指向托管或本机内存,也可以指向堆栈上分配的内存。
Memory <T>
是类型的补充Span<T>
。正如其设计文档中所讨论的那样,它Span<T>
是仅堆栈类型。的仅堆栈性质Span<T>
使它不适用于许多需要Span<T>
在堆上存储对缓冲区(用表示)的引用的情况,例如,进行异步调用的例程。
async Task DoSomethingAsync(Span<byte> buffer) {
buffer[0] = 0;
await Something(); // Oops! The stack unwinds here, but the buffer below
// cannot survive the continuation.
buffer[0] = 1;
}
为了解决这个问题,我们将提供一组互补类型, 这些类型将用作通用交换类型,这些类型代表
Span <T>
了一系列任意内存,但与Span <T>
这些类型不同的是,这些类型将不是仅堆栈的,而代价是读取和写入内存的性能损失。
async Task DoSomethingAsync(Memory<byte> buffer) {
buffer.Span[0] = 0;
await Something(); // The stack unwinds here, but it's OK as Memory<T> is
// just like any other type.
buffer.Span[0] = 1;
}
在上面的示例中,
Memory <byte>
用来表示缓冲区。它是常规类型,可以在进行异步调用的方法中使用。它的Span属性返回Span<byte>
,但是返回的值在异步调用期间不会存储在堆上,而是从该Memory<T>
值产生新的值。从某种意义上讲,Memory<T>
是的工厂Span<T>
。
参考文件:此处
Span<byte> buffer
示例中,我不明白为什么缓冲区不能在延续中幸免。为什么我们将地址松开到内存中buffer [0]指向的位置?
重新:这意味着它只能指向堆栈上分配的内存。
Span<T>
可以指向任何内存:分配在堆栈或堆上。仅堆栈的性质Span<T>
意味着其Span<T>
本身(而不是它指向的内存)必须仅驻留在堆栈上。这与“常规” C#结构相反,后者可以驻留在堆栈或堆上(通过值类型装箱,或者当它们嵌入在类/引用类型中时)。一些更明显的实际含义是,您不能Span<T>
在类中有一个字段,不能装箱Span<T>
,也不能将它们制成数组。
Memory
(至少不是直接分配给您),您可以尝试一下Memory<byte> mem = stackalloc byte[100];
并得到编译错误
Memory<T>
可以看作是不安全的但用途更广泛的版本Span<T>
。Memory<T>
如果对象指向已释放的数组,则访问将失败。