C#7.2引入了两种新类型:Span<T>
和Memory<T>
,它们比string[]
等早期C#类型具有更好的性能。
问题:Span<T>
和Memory<T>
之间有什么区别?为什么我会使用一个而不是另一个?
答案 0 :(得分:47)
Span<T>
本质上只是堆栈,而堆Memory<T>
可以存在。
Span<T>
是我们要添加到平台以表示的新类型 任意记忆的连续区域,具有性能 与T [相同的特征。它的API类似于数组, 但与数组不同,它可以指向托管或本机内存,或者 到堆栈上分配的内存。
Memory <T>
是补充Span<T>
的类型。正如其设计中所讨论的那样 documentSpan<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>
对象指向已释放的数组,则访问将失败。