系列介绍

简介

【五分钟的DotNet】是一个利用您的碎片化时间来学习和丰富.net知识的博文系列。它所包含了.net体系中可能会涉及到的方方面面,比如C#的小细节,AspnetCore,微服务中的.net知识等等。

5min+不是超过5分钟的意思,"+"是知识的增加。so,它是让您花费5分钟以下的时间来提升您的知识储备量。

正文

在dotnet core2.x之后,引入了一个叫做Span<T>的类型。如果您的项目已经升级到了新版的dotnet core 以及使用C# 7+。您会发现我们曾经使用的许许多多类型都增加了一个扩展方法“AsSpan()”。在Vs中小手一点就会出现:


var s = ("xxx").AsSpan();
var s1 = new byte[10].AsSpan();
//.......more

那么这个家伙到底是个什么东西?怎么用呢?

先来扒一扒它的内部方法:

public readonly ref struct Span<T>
{
public void Clear();
public void CopyTo([NullableAttribute(new[] { 0, 1 })] Span<T> destination);
public void Fill(T value);
public Enumerator GetEnumerator();
public Span<T> Slice(int start, int length);
public T[] ToArray();
public override string ToString(); //.....
}

这里只展示它部分的方法,但是关键的一点我们可以看到:它是一个结构性(struct 关键字)。

而且!!而且!!! 你没看错,它还加了一个ref关键字。

所以按照我们在上一篇文章中介绍过的 .net中的栈和堆,我们猜想这种结构类型的数据应该是存放在内存栈中,具有很快的访问速度。而且它拥有了ref关键字,证明它具有ref结构体的特点:

  • 不能对 ref struct 装箱
  • ref struct 类型不能实现接口
  • 不能将 ref struct 声明为类或常规结构的字段成员
  • 不能声明异步方法中属于 ref struct 类型的本地变量
  • 无法在迭代器中声明 ref struct 本地变量
  • 无法捕获 Lambda 表达式或本地函数中的 ref struct 变量

而且根据它公开的这些方法,我们会发现它有点类似我们常用的几个基础类型:string 、 byte[] ……。

所以直觉告诉我们,它应该是一个拿来存放数据的类型。

so,来看看MSDN - Magazine中它的解释:

System.Span<T> 是在 .NET 中发挥关键作用的新值类型。使用它,可以表示任意内存的相邻区域,无论相应内存是与托管对象相关联,还是通过互操作由本机代码提供,亦或是位于堆栈上。除了具有上述用途外,它仍能确保安全访问和高性能特性,就像数组一样。

果不其然,和我们猜想的一样。那么它出现的意义是什么呢? 性能!!!!

而且是超级快的性能。大家都知道以往如果我们想提高数据间的操作效率(比如数据偏移、裁剪等),就只能使用指针来操作内存中的数据。这样虽然一波操作猛如虎,但是写起来费劲不说,我们还得将传统的C#代码设置为不安全代码,除了添加unsafe关键字之外还需要打开项目中执行不安全代码的选项。

所以,有没有办法既不操作指针而又有高性能呢? 好吧,Span大爷来了。

Span在C# 7.x中被引入,所以它的年龄还算比较小,也是因为这些原因。以往的项目可能没有办法使用它。

它到底有多快

大家一般都是想直接看东西,所以我写了一份对比的代码。功能很简单,都是截取字符串中的一部分代码,并且进行多次的循环操作。

执行结果我都惊呆了:

是的,您没有看错。差距不是一般的大。

其实刚开始我以为Span并没有什么作用,因为我将数据源(图中的compareStr)仅仅设置为了几个单词。然后对他们进行了1亿的循环操作,但是最后的结果只有很小的差距,不到百分之30。

后来我想了一下,应该让数据更贴近现实,于是就将一张图片转换为base64然后作为数据源。结果惊呆了,差了接近百倍。而且随着循环次数和对数据源的操作次数的增多,Span和传统字符串之间的性能差距更大。

传说中的闪电光速拳到底有多快呢

它为什么这么快

它与传统的string操作比起来为什么会具有这么快的速度呢? 按照我们之前的一些猜想和msdn所给出的一点信息,我们可以得到以下的结论:

  • 它分配堆栈上而不是在托管堆。
  • 它所创建的数据是内存连续的,因此具有更快的遍历速度。

这些特点和string等原有类型比起来就非常的具有优势了:原来对string操作涉及到大量的字符串分配和内存复制。所以当操作的数据量小的时候还好,但是随着操作次数和处理数据量的增加之后,这是非常消耗性能的。

Span会给我们带来什么

那么,既然它拥有如此高的性能,那么我们该在什么地方使用它呢?

这很简单,如果您以前有对大量字符串进行截取或者处理的地方,一般都可以替换为Span。(为什么是一般呢

【5min+】闪电光速拳? .NetCore 中的Span的更多相关文章

  1. .NetCore中的日志(2)集成第三方日志工具

    .NetCore中的日志(2)集成第三方日志工具 0x00 在.NetCore的Logging组件中集成NLog 上一篇讨论了.NetCore中日志框架的结构,这一篇讨论一下.NetCore的Logg ...

  2. .NetCore中的日志(1)日志组件解析

    .NetCore中的日志(1)日志组件解析 0x00 问题的产生 日志记录功能在开发中很常用,可以记录程序运行的细节,也可以记录用户的行为.在之前开发时我一般都是用自己写的小工具来记录日志,输出目标包 ...

  3. AutoMapper在asp.netcore中的使用

    # AutoMapper在asp.netcore中的使用  automapper 是.net 项目中针对模型之间转换映射的一个很好用的工具,不仅提高了开发的效率还使代码更加简洁,当然也是开源的,htt ...

  4. netcore中的缓存介绍

    Cache(缓存)是优化web应用的常用方法,缓存存放在服务端的内存中,被所有用户共享.由于Cache存放在服务器的内存中,所以用户获取缓存资源的速度远比从服务器硬盘中获取快,但是从资源占有的角度考虑 ...

  5. 在netcore中如何注入同一个接口的多个实现

    netcore中自带了Ioc框架,这也影响了我们的编码习惯,以前都是静态类或者直接new对象,现在有了Ioc框架的支持,我们也不必守旧,应当使用起来,接受这种对象管理方式.使用过java的同仁,都习惯 ...

  6. .NetCore中EFCore的使用整理(二)-关联表查询

    EF常用处理关联加载的方式有3中:延迟加载(Lazy Loading).贪婪加载 (Eager Loading)以及显示加载. 一.EF Core  1.1 1.当前的版本,还不支持延迟加载(Lazy ...

  7. .NetCore中EFCore for MySql整理(三)之Pomelo.EntityFrameworkCore.MySql

    一.Pomelo.EntityFrameworkCore.MySql简介 Git源代码地址:https://github.com/PomeloFoundation/Pomelo.EntityFrame ...

  8. .NetCore中如何实现权限控制 基于Claim角色、策略、基于Claim功能点处理

    .NetCore中如果实现权限控制的问题,当我们访问到一个Action操作的时候,我们需要进行权限控制 基于claims 角色控制 基于角色控制总觉得范围有点过大,而且控制起来感觉也不是太好,举一个例 ...

  9. .NetCore中EFCore for MySql整理(二)

    一.简介 EF Core for MySql的官方版本MySql.Data.EntityFrameworkCore 目前正是版已经可用当前版本v6.10,对于以前的预览版参考:http://www.c ...

随机推荐

  1. 小程序与HTML5的区别

    小程序与传统HTML5还是有明显的区别,主要区别在于: 开发工具不同: 区别于H5的开发工具+浏览器Device Mode预览的模式,小程序的开发基于自己的开发者工具,可以实现同步本地文件+开发调试+ ...

  2. vue调用兄弟组件的方法使用vueBus调用$emit、$on(只需触发方法即可,不需要考虑传值或参数的问题)

    触发方: vueBus.$emit('queryAll') 被触发方: created() { vueBus.$on('queryAll', () => { this.getList() // ...

  3. SpringBoot2.0 使用AOP统一处理Web请求日志(完整版)

    一,加入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  4. Junit 测试集(打包测试)实例

    测试集,直译过来的意思就是把测试集合起来,再详细一些就是把多个单元测试集合起来 .单元测试可以理解为:单个接口 或者单个类/方法 的测试 项目背景:测试基于spring开发的项目代码 实例模板:pac ...

  5. C# 高级面试题

    很少会有人可以答对,如果你遇到一个来面试的人实在嚣张,就可以用本文的题去打击 本文内容就看着玩,请不要在严肃的面试中问题这样的题目 如果面试到一个人可以回答出下面的题目也不能证明他的技术很强,只能说明 ...

  6. Linux 内核 NuBus 总线

    另一个有趣的, 但是几乎被忘记的, 接口总线是 NuBus. 它被发现于老的 Mac 计算机(那 些有 M68K CPU 家族的). 所有的这个总线是内存映射的(象 M68K 的所有东西), 并且设备 ...

  7. Linux 内核PCI 中断

    对于中断, PCI 是容易处理的. 在 Linux 启动时, 计算机的固件已经分配一个唯一的中 断号给设备, 并且驱动只需要使用它. 中断号被存储于配置寄存器 60 (PCI_INTERRUPT_LI ...

  8. Storm使用总结

    Strom安装 Strom启动 ./zkServer.sh start 启动nimbus主节点: nohup bin/storm nimbus >> /dev/null & 启动s ...

  9. 使用eclipse运行maven web项目 插件/非插件

    一.使用插件 tomcat 8.5 tomcat-users.xml中添加这一行就ok <user username="admin" password="admin ...

  10. onCreate不加载布局

    如果Activity重写的是 onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentS ...