《ASP.NET Core 高性能系列》Span<T>和Memory<T>

一、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> 并且不能跨 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[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分配的而来的

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运行的指令更少了,减少了不必要的开销

原文地址:https://www.cnblogs.com/humble/p/12382833.html

时间: 2024-08-28 01:51:35

《ASP.NET Core 高性能系列》Span<T>和Memory<T>的相关文章

《ASP.NET Core 高性能系列》致敬伟大的.NET斗士甲骨文!

原文:<ASP.NET Core 高性能系列>致敬伟大的.NET斗士甲骨文! 写在开始 三年前,曾写过一篇文章:从.NET和Java之争谈IT这个行业,当时遭到某些自认为懂得java就了不起的Javaer抨击, 现在可以致敬伟大的.NET斗士甲骨文了 (JDK8以上都需要收费,Android弃用java作为第一语言,别高兴:OpenJDK是甲骨文的). <ASP.NET Core 高性能系列>是一套如何编写高性能Web应用技术系列文章, 我们将从.NET 2开始全面升入.其中我们会

《ASP.NET Core 高性能系列》静态文件中间件

原文:<ASP.NET Core 高性能系列>静态文件中间件 一.概述 静态文件(如 HTML.CSS.图片和 JavaScript等文件)是 Web程序直接提供给客户端的直接加载的文件. 较比于程序动态交互的代码而言,其实原理都一样(走Http协议), ASP.NET Core中需要进行一些配置才能提供这些文件. 二.wwwroot 静态文件存储在项目的 Web 程序的 {ContentRoot}/wwwroot目录下,但可通过 UseWebRoot 方法更改路径 . Web 应用程序项目的

《ASP.NET Core 高性能系列》环境(EnvironmentName)的设置

原文:<ASP.NET Core 高性能系列>环境(EnvironmentName)的设置 一.概述 程序启动时Host捕获到环境相关数据,然后交由IEnvironment(传说要作废,但是觉得这个设计依旧前后矛盾,因为没有考虑好非Web 和Web区分),然后交由IWebHostEnvironment,对于ASP.NET Core环境而言,同样会存储在 IWebHostEnvironment.EnvironmentName,ASP.NET Core框架自身提供Development.Stagi

《ASP.NET Core 高性能系列》关于.NET Core的配置信息的若干事项

1.配置文件的相关闲话 Core自身对于配置文件不是必须品,但由上文分析可知ASP.NET Core默认采用appsettings.json作为配置文件,关于配置信息的优先等级 命令行>环境变量>自我订制的配置(AddUserSecrets)>和当前环境相匹配的appsettings.json中的配置>大于appsettings.json中的配置 关于AddUserSecrets是什么这里简单一言以蔽之:每个开发人员有自己特性的配置数据,这些配置信息仅仅属于个人,不能提交给团队成员

《ASP.NET Core 高性能系列》关于.NET Core的部署方式

概述,.NET Core应用程序可以创建三种类型的部署:FDD SCD FDE 框架依赖的部署(FDD).顾名思义,框架依赖的部署(FDD)依赖于目标系统上是否存在.NET Core版本.由于.NET Core已经存在,因此您的应用程序在不同的.NET Core版本中进行移植.您的应用程序仅包含其自己的代码以及.NET Core库之外的任何第三方依赖项.FDD包含.dll文件,可以通过使用dotnet命令行启动这些文件. 例如,dotnet app.dll运行名为的应用程序app. 自包含的部署

《ASP.NET Core 高性能系列》ASP.NET Core的启动过程(1)

一.一切从头开始 简述:知道事情的真相就应该从头 开始,下面我们代码先行 public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWeb

《ASP.NET Core 高性能系列》关于性能的闲聊

一.通常的性能问题类型 让我们一起看看那些公共的性能问题,看看他们是或者不是.我们将了解到为什么我们常常在开发期间会错过这些问题.我们也会看看当我们考虑性能时语言的选择.延迟.带宽.计算等因素. 二.语言的考虑 人们经常关注所使用的编程语言的速度.然而,这经常没有抓住要点.这是一个非常简单的观点,掩盖了技术选择的细微差别,用任何语言编写速度慢的软件都很容易.由于当今计算机的处理速度非常强大,所以解释性能相对较慢的语言通常足够快,而开发中性能的提高是值得的.要理解所涉及的论点和权衡是很重要的,即使

ASP.NET Core学习系列

.NET Core ASP.NET Core ASP.NET Core学习之一 入门简介 ASP.NET Core学习之二 菜鸟踩坑 ASP.NET Core学习之三 NLog日志 ASP.NET Core学习之四 在CentOS上部署.net core LINUX学习系列 DOCKER学习系列 微服务学习系列 原文地址:https://www.cnblogs.com/xcsn/p/8306854.html

ASP.NET Core部署系列一:发布到IIS上

前言: 当构建一个ASP.NET Core应用程序并且计划将其运行在IIS中时,你会发现Core应用程序和之前版本的ASP.NET程序在IIS中的运行方式是完全不一样的.与ASP.NET时代不同,ASP.NET Core不再是由IIS工作进程(w3wp.exe)托管,而是使用自托管Web服务器(Kestrel)运行,IIS则是作为反向代理的角色转发请求到Kestrel不同端口的ASP.NET Core程序中,随后就将接收到的请求推送至中间件管道中去,处理完你的请求和相关业务逻辑之后再将HTTP响