title author date CreateTime categories
C# Span 入门
lindexi
2018-12-02 11:32:46 +0800
2018-06-18 11:15:43 +0800
C#

本文简单告诉大家如何使用 Span 新的功能
需要知道 Span 是 7.2 才有的功能,如果在正式项目使用,建议安装 Nuget 的方式

在对内存指定的一段的处理,原来的 C# 是比较弱的,因为没有了 C++ 的指针,特别是对于字符串的分割,需要创建多几个字符串。

垃圾微软为了提高 C# 的性能,于是提供了新的类型 Span,这个类可以拿出任意数组的一段,作为一个新的 Span 列表。这样的底层就是指针,而且指针是有判断是否超过范围比 C++ 安全。

首先安装 Nuget System.Memory 库,要求 dotnet framework 4.5 以上,在 UWP 16299 以上,在 dotnet core 2.0 以上

先来写一个简单的程序,创建一个数组,然后使用 Span 指定数组的某一段

            var array = new byte[10];
Span<byte> bytes = array;
bytes = bytes.Slice(start: 2, length: 5); bytes[0] = 5;
Console.WriteLine(array[2]);
Console.WriteLine(bytes[0]);

可以看到对 bytes[0] 的修改就是对 array[2] 的修改,这样可以做到数组重新计算。

也就是对某个计算,需要加上数组的移动,如二维数组的图片计算,例如行是 w 列是 h ,那么计算第 n 行的元素,在以前的时候,就需要在每个的前面加上 w*n,现在可以使用 spanList.Slice(start:w*n, Length:w) 这样重新拿到的数组就是一行,不需要在每个计算都需要添加很多代码

            var array = new byte[10];
Span<byte> bytes = array;
bytes = bytes.Slice(start: 2, length: 5); bytes[0] = 5;
Console.WriteLine(array[2]);
Console.WriteLine(bytes[0]); try
{
bytes[5] = 2;
}
catch (IndexOutOfRangeException e)
{
Console.WriteLine(e);
}

有了这个类就不需要担心写出超过范围代码

stackalloc

如果要和 stackalloc 需要打开不安全代码

然后点击生成高级,选择 C# 7.2 以上

现在可以写出这样的代码

        private static unsafe void DroosorHotir()
{
Span<byte> bytes = stackalloc byte[2];
bytes[0] = 2;
bytes[1] = 3; Console.WriteLine(bytes[0]);
Console.WriteLine(bytes[1]);
}

调用这个函数可以输出 2 和 3 ,使用 stackalloc 可以比申请数组使用更少的资源。因为默认申请的数组都在堆中,不使用需要 gc 才可以回收。但是 stackalloc 可以在变量所在函数结束之后直接就回收,不需要移动内存。

但是 stackalloc 容易出现堆栈溢出,请执行下面的代码,堆栈溢出是 catch 也无法让他不让程序直接退出

            Span<double> bytes = stackalloc double[200000];

即使使用 catch ,软件也会直接退出

            try
{
Span<double> bytes = stackalloc double[200000];
}
catch (Exception)
{
// 接不住
}

AllocHGlobal

除了使用 stackalloc 之外,还可以使用 Marshal.AllocHGlobal 申请一段内存

            IntPtr ptr = Marshal.AllocHGlobal(2);
try
{
var bytes = new Span<byte>((byte*) ptr, 2) {[0] = 42}; Console.WriteLine(bytes[0]);
Console.WriteLine(Marshal.ReadByte(ptr));
}
finally
{
Marshal.FreeHGlobal(ptr);
}

需要注意,申请的内存都需要自己释放

而且需要注意,不要使用比自己申请的内存大的数组

            IntPtr ptr = Marshal.AllocHGlobal(2);
var bytes = new Span<byte>((byte*) ptr, 1000) {[0] = 42};

上面代码申请了内存为 2 但是下一句使用了1000长度

                for (int i = 0; i < 1000; i++)
{
bytes[i] = 25;
Console.WriteLine(bytes[i]);
}

这时虽然很多次都可以赋值成功,但是运行到某个时候,软件就直接退出。

参考:

C# - All About Span: Exploring a New .NET Mainstay

通俗易懂,C#如何安全、高效地玩转任何种类的内存之Span(一)

2018-12-2-C#-Span-入门的更多相关文章

  1. 2018.12.02 Socket编程之初识Socket

    Socket编程主要分为TCP/UDP/SCTP三种,每一种都有各自的优点,所以会根据实际情况决定选用何种Socket,今天开始我将会逐步学习Socket编程,并将学习过程记录于此. 今天学习的是TC ...

  2. OPPO Developers Conference(2018.12.26)

    时间:2018.12.26地点:北京国家会议中心

  3. Tencent Cloud Developers Conference(2018.12.15)

    时间:2018.12.15地点:北京朝阳悠唐皇冠假日酒店

  4. 2018.12.1 Test

    目录 2018.12.1 Test A 串string(思路) B 变量variable(最小割ISAP) C 取石子stone(思路 博弈) 考试代码 B C 2018.12.1 Test 题目为2 ...

  5. 「版本升级」MyEclipse CI 2018.12.0正式发布

    新版本MyEclipse为WildFly 14新增一个新的服务器连接器,改进性能并新增一些Java 10修复程序.新版本为IDE做了几个核心修复,这是MyEclipse 2018一个更棒的升级. [M ...

  6. 微信小程序 - 接口更新记录以及解决方案(2018/12/26)

    2018/8/17 - 背景音频需要在app.json添加requireBackGroundModes 2018/9/12 - 微信更改获取用户信息接口/获取位置等接口 - button 2018/1 ...

  7. 调试大叔V2.1.0(2018.12.17)|http/s接口调试、数据分析程序员辅助开发神器

    2018.12.17 - 调试大叔 V2.1.0*升级http通讯协议版本,完美解决Set-Cookie引起的系列问题:*新增Content-Type编码格式参数,支持保存(解决模拟不同网站或手机请求 ...

  8. C# Span 入门

    原文:C# Span 入门 版权声明:博客已迁移到 http://lindexi.gitee.io 欢迎访问.如果当前博客图片看不到,请到 http://lindexi.gitee.io 访问博客.本 ...

  9. loli的测试-2018.12.9

    模拟赛-2018.12.9 这是NOIP之后第一次模拟赛...但是考的比较悲惨. 非常喜欢写考试总结,不知道为什么... T1:https://www.luogu.org/problemnew/sho ...

  10. 2018.12.7 浪在ACM 集训队第八次测试赛

    2018.12.7 浪在ACM 集训队第八次测试赛  https://blog.csdn.net/QLU_minoz/article/details/84886717   感谢苗学林同学C题和D题题解 ...

随机推荐

  1. Python基础篇(set集合)

    Python基础篇(set集合,深浅拷贝) set集合是Python的一个基本类型,一般是不常用.set中的元素是不重复的.无序的里边 的元素必须是可hash的比如int,str,tuple,bool ...

  2. WPFの多屏幕问题

    public MainWindow(string sysName, int timeState) { InitializeComponent(); //查找当前屏幕数量 ) { Dispatcher. ...

  3. Java 编程技巧之数据结构

    前言: 介绍几种常见的java数据结构及应用. 使用HashSet判断主键是否存在 HashSet 实现 Set 接口,由哈希表(实际上是 HashMap )实现,但不保证 set  的迭代顺序,并允 ...

  4. MAC如何与linux服务器传递文件

    scp命令可以从本地拷贝文件到Linux服务器,也可以将Linux服务器文件下载到本地 将远程/root/articaleFetch/dist目录下文件和文件夹拷贝到dist文件夹 scp root@ ...

  5. C# IOC DI 学习

    之前一直不理解IOC DI,今天使劲研究了下,感觉朦朦胧胧有点感觉了,网上的这篇文章对我的有很大的启发 http://www.cnblogs.com/jin-yuan/p/3823559.html 我 ...

  6. vue.config.js配置前端代理

    // vue.config.js 配置说明 //官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions // 这 ...

  7. event(1)

    event event(事件流)是 window对象的一个属性 在JS中事件有2种类型 一种是冒泡类型 一种是捕获类型 冒泡类型最先是在IE中出现,而捕获类型最先在标准的DOM中出现,不过最终IE得胜 ...

  8. java--字符串拼接比较

    /** * 字符串拼接 */ public class StringAddDemo { public static void main(String[] args){ testStringAdd(); ...

  9. Mybatis配置——自动使用驼峰命名 属性映射字段(默认为false)

    开发一个新项目,用的springboot,相关配置不太熟悉,导致一些配置没配,到具体开发时问题就暴露出来了,记录第一个配置问题----Mybatis配置-自动使用驼峰命名 属性(userId)映射字段 ...

  10. oracle 批处理 bulk collect 带来的性能优势

    create table -- drop table tmp_20190706_220000-- truncate table tmp_20190706_220000 create table tmp ...