《ASP.NET Core 高性能系列》Span<T>和Memory<T>
一、Span<T>概述
原文:Provides a type- and memory-safe representation of a contiguous region of arbitrary memory.
中文的翻译不准确,这里给出比较厚道的翻译:提供类型T安全、连续的内存区域的表达方式.

这里出现高阶语法 readonly ref struct,下面是msdn给的语言规范(或者其核心意义),估计大家会看晕,
Span<T> 并且不能跨 await 和 yield 边界使用。 此外,对两个方法的调用(Equals(Object) 和 GetHashCode)将引发一个 NotSupportedException。因为锁定在堆栈上,所以也不要试图让其成为做为静态成员。
我先给出最简单的解释:
Span<T>是微软为了给.NET提供了一个高效的内存操纵元素,而定义的一个数据结构,为了高效的初衷,将Span<T>自身锁定在堆栈上(内存连续,且处理高效)
注意:是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[];
Span<int> arraySpan = array; Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int ctr = ; ctr < arraySpan.Length; ctr++)
arraySpan[ctr] = arraySpan[ctr] * arraySpan[ctr]/;
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed); array = new int[];
stopwatch.Reset();
stopwatch.Start();
for (int ctr = ; ctr < array.Length; ctr++)
array[ctr] = array[ctr] * array[ctr]/;
Console.WriteLine(stopwatch.Elapsed);
结果按照我们的原则你就知道,不用Span效果会更好,下图是realse模式下发布的,整体上可知:不用Span会更快,所以切片是它的本质!大家看看GO的切片就知道了.

3.1 Span<T>可以不仅投影常见对象还可以是从Marshal , stackalloc分配的而来的
var native = Marshal.AllocHGlobal(100);
Span<byte> nativeSpan;
unsafe
{
nativeSpan = new Span<byte>(native.ToPointer(), 100);
}
byte data = 0;
for (int ctr = 0; ctr < nativeSpan.Length; ctr++)
nativeSpan[ctr] = data++; int nativeSum = 0;
foreach (var value in nativeSpan)
nativeSum += value; Console.WriteLine($"The sum is {nativeSum}");
Marshal.FreeHGlobal(native);
byte data = 0;
Span<byte> stackSpan = stackalloc byte[100];
for (int ctr = 0; ctr < stackSpan.Length; ctr++)
stackSpan[ctr] = data++; int stackSum = 0;
foreach (var value in stackSpan)
stackSum += value; Console.WriteLine($"The sum is {stackSum}");
三、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运行的指令更少了,减少了不必要的开销
《ASP.NET Core 高性能系列》Span<T>和Memory<T>的更多相关文章
- 《ASP.NET Core 高性能系列》致敬伟大的.NET斗士甲骨文!
写在开始 三年前,曾写过一篇文章:从.NET和Java之争谈IT这个行业,当时遭到某些自认为懂得java就了不起的Javaer抨击, 现在可以致敬伟大的.NET斗士甲骨文了 (JDK8以上都需要收费, ...
- 《ASP.NET Core 高性能系列》关于.NET Core的配置信息的若干事项
1.配置文件的相关闲话 Core自身对于配置文件不是必须品,但由上文分析可知ASP.NET Core默认采用appsettings.json作为配置文件,关于配置信息的优先等级 命令行>环境变量 ...
- 《ASP.NET Core 高性能系列》关于.NET Core的部署方式
概述,.NET Core应用程序可以创建三种类型的部署:FDD SCD FDE 框架依赖的部署(FDD).顾名思义,框架依赖的部署(FDD)依赖于目标系统上是否存在.NET Core版本.由于.NET ...
- 《ASP.NET Core 高性能系列》ASP.NET Core的启动过程(1)
一.一切从头开始 简述:知道事情的真相就应该从头 开始,下面我们代码先行 public class Program { public static void Main(string[] args) { ...
- 《ASP.NET Core 高性能系列》静态文件中间件
一.概述 静态文件(如 HTML.CSS.图片和 JavaScript等文件)是 Web程序直接提供给客户端的直接加载的文件. 较比于程序动态交互的代码而言,其实原理都一样(走Http协议), ASP ...
- 《ASP.NET Core 高性能系列》环境(EnvironmentName)的设置
一.概述 程序启动时Host捕获到环境相关数据,然后交由IEnvironment(传说要作废,但是觉得这个有设计点问题,因为.NET Core 非Web怎么处理?),然后交由IWebHostEnvir ...
- 《ASP.NET Core 高性能系列》关于性能的闲聊
一.通常的性能问题类型 让我们一起看看那些公共的性能问题,看看他们是或者不是.我们将了解到为什么我们常常在开发期间会错过这些问题.我们也会看看当我们考虑性能时语言的选择.延迟.带宽.计算等因素. 二. ...
- 跟我学: 使用 fireasy 搭建 asp.net core 项目系列之一 —— 开篇
==== 目录 ==== 跟我学: 使用 fireasy 搭建 asp.net core 项目系列之一 —— 开篇 跟我学: 使用 fireasy 搭建 asp.net core 项目系列之二 —— ...
- 跟我学: 使用 fireasy 搭建 asp.net core 项目系列之三 —— 配置
==== 目录 ==== 跟我学: 使用 fireasy 搭建 asp.net core 项目系列之一 —— 开篇 跟我学: 使用 fireasy 搭建 asp.net core 项目系列之二 —— ...
随机推荐
- sftp安装(linux)
--整理于网络 1. 查看openssh版本ssh -Vopenssh版本必须大于4.8p12. 创建sftp组groupadd sftp3. 创建sftp用户useradd -g sftp -s / ...
- linux4.11内核设备编译时出现的问题(参考博客并更改的)
AllWinnerH3 linux4.11版本的bsp下载: https://pan.baidu.com/s/1mhU4a8K 密码: b375 H3-linux4.11_bsp目录就是所需的源码及编 ...
- [LC] 93. Restore IP Addresses
Given a string containing only digits, restore it by returning all possible valid IP address combina ...
- CentOS6与CentOS7的启动过程
Linux启动流程CentOS6的启动流程Systemd概述Systemd初始化进程Systemd目标名称systemd服务管理 linux系统的组成:内核+跟文件系统 内核可实现以下功能:进程管理. ...
- IntelliJ的.iml文件及相关的Class Not Found 问题
.iml 文件是IntelliJ IDEA 自动创建的模块文件,用于Java应用开发,存储一些模块开发相关的信息,比如一个Java组件, 插件组件,Maven组件等等, 还可能会存储一些模块路径信息, ...
- numpy矩阵运算--矩阵乘法
1)元素对应相乘,使用 multiply 函数或 * 运算符来实现 a = np.array([2,2,2])b = np.array([3,3,3]) c1 = a*a c1 array([4, 4 ...
- 吴裕雄--天生自然 R语言开发学习:数据集和数据结构
数据集的概念 数据集通常是由数据构成的一个矩形数组,行表示观测,列表示变量.表2-1提供了一个假想的病例数据集. 不同的行业对于数据集的行和列叫法不同.统计学家称它们为观测(observation)和 ...
- FPGA大疆考试准备内容
1.寄存器与锁存器 锁存器:电平触发的存储单元,在有效电平时间里可以多次改变数据. 优点: 占触发器资源少,缺点是容易产生毛刺.(附上去毛刺的方法:格雷码计数器(*https://blog.cs ...
- Hashtable和Hashmap的区别?
1.实现的继承的父类不同 Hashtable继承Dictionary类 HashMap继承abstractMap类 两个类都实现了Map接口 2.线程安全性不同 Hashmap线程是不安全的 H ...
- ViewPager 和 SwipeRefreshLayout 的滑动冲突
如题,当SwipeRefreshLayout包裹ViewPager时,发现ViewPager经常滑不动,容易把上面的刷新的小圈圈拽出来,只有手指在屏幕上向斜上方滑或者水平滑动,才能保持正常,这是一个滑 ...
