原文:C# Span 入门

版权声明:博客已迁移到 http://lindexi.gitee.io 欢迎访问。如果当前博客图片看不到,请到 http://lindexi.gitee.io 访问博客。本文地址 https://blog.csdn.net/lindexi_gd/article/details/84251753

本文简单告诉大家如何使用 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

我搭建了自己的博客 https://lindexi.gitee.io/ 欢迎大家访问,里面有很多新的博客。只有在我看到博客写成熟之后才会放在csdn或博客园,但是一旦发布了就不再更新

如果在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎大家加入


本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

C# Span 入门的更多相关文章

  1. .NET/C# 使用 Span 为字符串处理提升性能

    .NET Core 2.1 和 C# 7.2 带来了 Span 的原生支持,原本需要使用不安全代码操作的内存块现在可以使用安全的方式来完成.此前在性能和稳定性上需要有所取舍,而现在可以兼得了. 简单的 ...

  2. 2018-12-2-C#-Span-入门

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

  3. C# 标准性能测试

    经常我写一个类,作为一个工具类,小伙伴会问我这个类的性能,这时我就需要一个标准的工具进行测试. 本文告诉大家如何使用 benchmarkdotnet 做测试. 现在在 github 提交代码,如果有小 ...

  4. [业界方案] 用SOFATracer学习分布式追踪系统Opentracing

    [业界方案] 用SOFATracer学习分布式追踪系统Opentracing 目录 [业界方案] 用SOFATracer学习分布式追踪系统Opentracing 0x00 摘要 0x01 缘由 &am ...

  5. [业界方案]用Jaeger来学习分布式追踪系统Opentracing

    [业界方案]用Jaeger来学习分布式追踪系统Opentracing 目录 [业界方案]用Jaeger来学习分布式追踪系统Opentracing 0x00 摘要 0x01 缘由 & 问题 1. ...

  6. [HeadFirst-HTMLCSS入门][第十章div,span]

    新元素 <div>逻辑容器 能进行分组,等于用一个大的盒子进行包装 <span> 内联字符的逻辑分组 text-align 改变所有内联元素位置. 属性 center 居中 行 ...

  7. Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数

    上一篇:Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数 之前介绍了简单的路由以及传参,这篇文章我们将要学习复杂一些的路由以及传递其他附加参数.一个好的路由系统可以使我们 ...

  8. Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数

    上一篇:Angular2入门系列教程-服务 上一篇文章我们将Angular2的数据服务分离出来,学习了Angular2的依赖注入,这篇文章我们将要学习Angualr2的路由 为了编写样式方便,我们这篇 ...

  9. SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=》提升)

     SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=>提升,5个Demo贯彻全篇,感兴趣的玩才是真的学) 官方demo:http://www.asp.net/si ...

随机推荐

  1. Vim 模式及常用命令整理

    VIM 命令     以:和/开头的命令都有历史纪录,可以首先键入:或/然后按上下箭头来选择某个历史命令.   vim的模式 基本上可以分为3种模式,分别是命令模式(command mode).插入模 ...

  2. jQuery----鼠标移动、点击案例

    单击隐藏: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <tit ...

  3. 10.6 android输入系统_Dispatcher线程_总体框架

    图解Android - Android GUI 系统 (5) - Android的Event Input System - 漫天尘沙 - 博客园.htm // 关注里面的Dispatcher处理流程h ...

  4. ORACLE表空间的备份与恢复策略

    转自原文如何进行ORACLE表空间的备份与恢复? 1.切换服务器归档模式,如果已经是归档模式可跳过此步: %sqlplus /nolog (启动sqlplus) SQL> conn / as s ...

  5. php课程 1-3 字符串变量输出方式有哪些(总结:四种)

    php课程 1-3 字符串变量输出方式有哪些(总结:四种) 一.总结 一句话总结:推荐使用双引号中加{$变量名}的形式(echo "my name is {$name}eee !" ...

  6. 数据结构与算法实验题 4.2 Who is the strongest

    数据结构与算法实验题 4.2 Who is the strongest ★实验任务 在神奇的魔法世界,召唤师召唤了一群的魁偶.这些魁偶排成一排,每个魁偶都有一个 战斗值.现在该召唤师有一个技能,该技能 ...

  7. FireBreath与JS交互1

    FireBreath提供接口供JS调用,提供的接口需要注册 必须在JSAPI对象的构造函数中注册,也就是 CxxxAPI::CxxxAPI()这个函数中调用 registerMethod(" ...

  8. 【u248】交通序列号

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 在一条笔直的道路上共有N个路口,每个路口处都有关于该条道路的通行的信号灯. 显然,信号灯共有绿(G). ...

  9. C运行时库(C Run-time Library)详解(提供的另一个最重要的功能是为应用程序添加启动函数。Visual C++对控制台程序默认使用单线程的静态链接库,而MFC中的CFile类已暗藏了多线程)

    一.什么是C运行时库 1)C运行时库就是 C run-time library,是 C 而非 C++ 语言世界的概念:取这个名字就是因为你的 C 程序运行时需要这些库中的函数. 2)C 语言是所谓的“ ...

  10. sigmoid function vs softmax function

    DIFFERENCE BETWEEN SOFTMAX FUNCTION AND SIGMOID FUNCTION 二者主要的区别见于, softmax 用于多分类,sigmoid 则主要用于二分类: ...