C# 7.2 引入了两种新类型:它们比早期的 C# 类型(Span<T>
如.Memory<T>
string[]
问题:Span<T>
和 和有什么不一样Memory<T>
?为什么我要使用其中一个?
C# 7.2 引入了两种新类型:它们比早期的 C# 类型(Span<T>
如.Memory<T>
string[]
问题:Span<T>
和 和有什么不一样Memory<T>
?为什么我要使用其中一个?
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>
。
参考文件:这里
re:这意味着它只能指向分配在堆栈上的内存。
Span<T>
可以指向任何内存:分配在堆栈或堆上。仅堆栈性质Span<T>
意味着它Span<T>
本身(而不是它指向的内存)必须仅驻留在堆栈上。这与“普通”C# 结构形成对比,后者可以驻留在堆栈或堆上(通过值类型装箱,或者当它们嵌入到类/引用类型中时)。一些更明显的实际含义是你不能Span<T>
在一个类中拥有一个字段,你不能 box Span<T>
,你不能将它们组成一个数组。
Memory<T>
可以被视为不安全但更通用的Span<T>
. Memory<T>
如果对象指向一个已释放的数组,则访问该对象将失败。