C#7.2中的Span <T>和Memory <T>有什么区别?


72

C#7.2引入了两种新类型:Span<T>Memory<T>具有比诸如C的早期C#类型更好的性能string[]

问题:Span<T>和之间有什么区别Memory<T>?为什么我要一个使用另一个?



2
@JeffMercado除了字符串[]之外,还有哪些可以替换的C#类型的完整列表?它们是仅用于数组还是可以代替List <T>之类的类型使用?
DarthVegan

Answers:


65

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>

参考文件:此处


9
“仅堆栈性质”是什么意思?
谜团

4
菜鸟在这里。堆栈不会回滚到等待之前的位置吗?在该Span<byte> buffer示例中,我不明白为什么缓冲区不能在延续中幸免。为什么我们将地址松开到内存中buffer [0]指向的位置?
Spectraljump

2
@Spectraljump如果我没记错的话,异步方法中的任何变量实际上都将是编译后的类字段(因此,在堆上),以便能够在等待后使用这些值。如果Span只能位于堆栈中,则等待之前和之后的Span都不相同。
krimog

39

重新:这意味着它只能指向堆栈上分配的内存。

Span<T>可以指向任何内存:分配在堆栈或堆上。仅堆栈的性质Span<T>意味着其Span<T>本身(而不是它指向的内存)必须仅驻留在堆栈上。这与“常规” C#结构相反,后者可以驻留在堆栈或堆上(通过值类型装箱,或者当它们嵌入在类/引用类型中时)。一些更明显的实际含义是,您不能Span<T>在类中有一个字段,不能装箱Span<T>,也不能将它们制成数组。


啊,另一种类似byref的类型。
IllidanS4支持Monica 17'Nov

1
但是为什么它只能驻留在Stack上?为什么不能把它们装箱?还是不能让他们上课?
ANewGuyInTown

4
如果您可以在堆上的任何地方(通过拳击,类的成员...)获得Span <T>,则堆上将有一个对象,该对象可以指向堆栈上的内存,当该对象在,例如,函数已返回。然后,您将有一个指向已释放内存的堆对象。可能导致段错误。
Mor A.

5
@ M.Aroosi-Memory <T>的情况不一样吗?Memory <T>可以驻留在堆上,并且可以指向堆栈中的内存,不是吗?这两个的新手并试图理解它。
pep

4
@pep您不能将堆栈分配的缓冲区分配给Memory(至少不是直接分配给您),您可以尝试一下Memory<byte> mem = stackalloc byte[100];并得到编译错误
Shmil The Cat

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.