在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
一、Span<T>概述原文:Provides a type- and memory-safe representation of a contiguous region of arbitrary memory. 中文的翻译不准确,这里给出比较厚道的翻译:提供类型T安全、连续的内存区域的表达方式. (图1:Span<T>定义,不是全图)
这里出现高阶语法 readonly ref struct,下面是msdn给的语言规范(或者其核心意义),估计大家会看晕,
我先给出最简单的解释: Span<T>是微软为了给.NET提供了一个高效的内存操纵元素,而定义的一个数据结构,为了高效的初衷,将Span<T>自身锁定在堆栈上(内存连续,且处理高效) 注意:是Span<T>自身!!! 二、Span<T>可用来做哪些事2.1 不得不提的 Slice 切片这种东西,在GO,Rust中太寻常了(PS:当然对于C++的表示不屑),对于C#而言,这是一个性能提升不可或缺的概念, Span基本上就是这个概念的翻版.所以其中有诸多方法就是切片.
可见微软为Span提供了诸多类似于原来的String中的很多方法,具体查阅地址: Span的扩展方法
2.1 切片是其本质,是对原有对象的投影(或部分投影) 之前我们要实现高效的操作,如字符串类的操作,数组类的操作, 这里应该尤其注意,不见得你使用Span就高效了,明白它的设计初衷:Slice! 特别是会不断产生新的碎片和构造新对象的场景.(由此可见对于String的操作产生了诸多 新碎片这样的场景是尤其好用的) 我们看看如下的场景,大家觉得哪个效率会更高 int[] array = new int[10000]; Span<int> arraySpan = array; Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); for (int ctr = 0; ctr < arraySpan.Length; ctr++) arraySpan[ctr] = arraySpan[ctr] * arraySpan[ctr]/3; stopwatch.Stop(); Console.WriteLine(stopwatch.Elapsed); array = new int[10000]; stopwatch.Reset(); stopwatch.Start(); for (int ctr = 0; ctr < array.Length; ctr++) array[ctr] = array[ctr] * array[ctr]/3; Console.WriteLine(stopwatch.Elapsed); 结果按照我们的原则你就知道,不用Span效果会更好,下图是realse模式下发布的,整体上可知:不用Span会更快,所以切片是它的本质!大家看看GO的切片就知道了.
3.1 Span<T>可以不仅投影常见对象还可以是从Marshal , stackalloc分配的而来的
三、Memory<T>概述和Span<T>类似,它同样表示连续内存区域。区别是没有Span<T>堆栈上的限制,没有 readonly ref struct 这样的申明了. 这意味着 Memory<T> 可以放置在托管堆上,而 Span<T> 不能。 因此,Memory<T> 结构与 Span<T> 实例没有相同的限制。 具体而言:它可用作类中的字段。它可跨 await 和 yield 边界使用。除了 Memory<T>之外,还可以使用 System.ReadOnlyMemory<T> 来表示不可变或只读内存。
这里有园友从C++源码的角度进行分析,这里提取下面两段,供大家参阅(链接地址), Span 与 Memory 的区别: 1.Memory<T> 保存 原有的对象地址、子内容的开始地址 与 子内容的长度,大致情况下图:
如上文所说,Span被微软锁定在堆栈上, 2.Span 保存子内容的开始地址与长度,不保存原始对象的地址,大致如下图:
如果这就是真实情况,可见Span脱离不了堆栈的环境的,不然计算不了真实的切片地址的.
三、使用上的预测和建议1.类似于string这样的操作会Span大有用处(因为会产生很多新的中间数据产生开销) 2.无论span还是memory设计初衷就是Slice,使用场景是那些会不断产生新的开销、新的对象的场景. 3.其实所有的性能提升根本让CPU运行的指令更少了,减少了不必要的开销
一、Span<T>概述原文:Provides a type- and memory-safe representation of a contiguous region of arbitrary memory. 中文的翻译不准确,这里给出比较厚道的翻译:提供类型T安全、连续的内存区域的表达方式. (图1:Span<T>定义,不是全图)
这里出现高阶语法 readonly ref struct,下面是msdn给的语言规范(或者其核心意义),估计大家会看晕,
我先给出最简单的解释: Span<T>是微软为了给.NET提供了一个高效的内存操纵元素,而定义的一个数据结构,为了高效的初衷,将Span<T>自身锁定在堆栈上(内存连续,且处理高效) 注意:是Span<T>自身!!! 二、Span<T>可用来做哪些事2.1 不得不提的 Slice 切片这种东西,在GO,Rust中太寻常了(PS:当然对于C++的表示不屑),对于C#而言,这是一个性能提升不可或缺的概念, Span基本上就是这个概念的翻版.所以其中有诸多方法就是切片.
可见微软为Span提供了诸多类似于原来的String中的很多方法,具体查阅地址: Span的扩展方法
2.1 切片是其本质,是对原有对象的投影(或部分投影) 之前我们要实现高效的操作,如字符串类的操作,数组类的操作, 这里应该尤其注意,不见得你使用Span就高效了,明白它的设计初衷:Slice! 特别是会不断产生新的碎片和构造新对象的场景.(由此可见对于String的操作产生了诸多 新碎片这样的场景是尤其好用的) 我们看看如下的场景,大家觉得哪个效率会更高 int[] array = new int[10000]; Span<int> arraySpan = array; Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); for (int ctr = 0; ctr < arraySpan.Length; ctr++) arraySpan[ctr] = arraySpan[ctr] * arraySpan[ctr]/3; stopwatch.Stop(); Console.WriteLine(stopwatch.Elapsed); array = new int[10000]; stopwatch.Reset(); stopwatch.Start(); for (int ctr = 0; ctr < array.Length; ctr++) array[ctr] = array[ctr] * array[ctr]/3; Console.WriteLine(stopwatch.Elapsed); 结果按照我们的原则你就知道,不用Span效果会更好,下图是realse模式下发布的,整体上可知:不用Span会更快,所以切片是它的本质!大家看看GO的切片就知道了.
3.1 Span<T>可以不仅投影常见对象还可以是从Marshal , stackalloc分配的而来的
三、Memory<T>概述和Span<T>类似,它同样表示连续内存区域。区别是没有Span<T>堆栈上的限制,没有 readonly ref struct 这样的申明了. 这意味着 Memory<T> 可以放置在托管堆上,而 Span<T> 不能。 因此,Memory<T> 结构与 Span<T> 实例没有相同的限制。 具体而言:它可用作类中的字段。它可跨 await 和 yield 边界使用。除了 Memory<T>之外,还可以使用 System.ReadOnlyMemory<T> 来表示不可变或只读内存。
这里有园友从C++源码的角度进行分析,这里提取下面两段,供大家参阅(链接地址), Span 与 Memory 的区别: 1.Memory<T> 保存 原有的对象地址、子内容的开始地址 与 子内容的长度,大致情况下图:
如上文所说,Span被微软锁定在堆栈上, 2.Span 保存子内容的开始地址与长度,不保存原始对象的地址,大致如下图:
如果这就是真实情况,可见Span脱离不了堆栈的环境的,不然计算不了真实的切片地址的.
三、使用上的预测和建议1.类似于string这样的操作会Span大有用处(因为会产生很多新的中间数据产生开销) 2.无论span还是memory设计初衷就是Slice,使用场景是那些会不断产生新的开销、新的对象的场景. 3.其实所有的性能提升根本让CPU运行的指令更少了,减少了不必要的开销
|
请发表评论