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

时间:2017-11-16 04:34:28

标签: c# c#-7.2 system.memory

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

问题:Span<T>Memory<T>之间有什么区别?为什么我会使用一个而不是另一个?

3 个答案:

答案 0 :(得分:47)

Span<T>本质上只是堆栈,而堆Memory<T>可以存在。

  

Span<T>是我们要添加到平台以表示的新类型   任意记忆的连续区域,具有性能   与T [相同的特征。它的API类似于数组,   但与数组不同,它可以指向托管或本机内存,或者   到堆栈上分配的内存。

     

Memory <T>是补充Span<T>的类型。正如其设计中所讨论的那样   document 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>的工厂。

参考文件:here

答案 1 :(得分:27)

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

Span<T>可以指向任何内存:在堆栈或堆上分配。 Span<T>的仅堆栈特性意味着Span<T>本身(不是它指向的内存)必须仅驻留在堆栈上。这与&#34; normal&#34;形成鲜明对比。 C#结构,可以驻留在堆栈上或堆上(通过值类型装箱,或者它们嵌入在类/引用类型中)。一些更明显的实际意义是你不能在一个类中有Span<T>字段,你不能框Span<T>,你也不能创建它们的数组。

答案 2 :(得分:-2)

Memory<T>可以看作是Span<T>的不安全但用途更广泛的版本。如果Memory<T>对象指向已释放的数组,则访问将失败。