Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >解读 --- Span<T>

解读 --- Span<T>

作者头像
Niuery Diary
发布于 2023-10-22 08:51:57
发布于 2023-10-22 08:51:57
20300
代码可运行
举报
运行总次数:0
代码可运行

引言

Span<T> 是C# 中的一种结构体,它是一种内存安全的类型,可以用来表示连续的内存区域。Span<T> 可以被用于访问和操作数组、堆上分配的内存和栈上分配的内存。使用 Span<T> 可以避免不必要的内存拷贝,从而提高性能。

对数组使用Span

如果需要快速访问托管或非托管的连续内存,可以使用 Span<T>结构。Span<T> 结构表示存储连续的内存。所以使用它的数据结构一般也使用连续的内存。例如:

  • 数组
  • 长字符串(实际上也是数组)

「使用 Span<T>,可以直接访问数组元素。且数组的元素不会复制,可以直接使用它们,这样比复制效率要高」。例如下面的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static void Main(string[] args)
{
    int[] source = new int[] { 1, 2, 3 };

    int[] arr = new int[] { source[0], source[1], source[2] };
    
    arr[0] = 33;
    
    Console.WriteLine($"The first element of source is {source[0]}");
    Console.WriteLine($"The first element of arr is {arr[0]}");

    Span<int> span = new(source);
    
    span[0] = 11;
    
    Console.WriteLine($"The first element of source is {arr[0]}");
    Console.WriteLine($"The first element of span is {span[0]}");
    
    Console.ReadLine();
}

可以先猜测以下上述代码的输出是什么?

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
The first element of source is 1
The first element of arr is 33
The first element of source is 11
The first element of span is 11

上述代码段中,先声明了一个源数组 source 和一个数组 arr ,并将 source 的值复制给 arr 。然后修改 arr 中的第一个元素值为33,可以看到结果 arr 的第一个元素已经改变为33,source 保持不变。然后又声明了一个 Span<int> ,它引用 source 数组。因为Span<T>是直接访问数组元素,而不是复制元素,所以修改 span 中的第一个元素为11, source 中的第一个元素也被修改为11。

创建切片

Span<T> 的一个强大特性是,可以使用它访问数组的部分或切片。使用切片时,不会复制数组元素,它们是从span 中直接访问的。

有如下代码段:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static void Main(string[] args)
{
    int[] source = { 1, 6, 23, 76, 88, 213 };
    
    Span<int> span1 = new Span<int>(source, start: 1, length: 4);
    
    Span<int> span2 = span1.Slice(start: 1, length: 3);
    
    DisplaySpan("span1 contains the elements:", span1);
    
    DisplaySpan("span2 contains the elements:", span2);
    
    Console.ReadLine();
}

private static void DisplaySpan(string content, Span<int> span1)
{
    Console.Write(content);
    
    foreach (var item in span1)
    {
        Console.Write(item + ",");
    }
    
    Console.WriteLine();
}

下面的代码片段展示了创建切片的两种方法。

  1. 除默认构造函数传参数组之外,另一种重载是直接使用构造函数传递源数组,起始位置和长度。例如上述代码中 new Span<int>(source, start: 1, length: 4) 它表示在源数组中从第2个元素开始访问数组的4个元素。
  2. 直接从span中再次切片,传入起始位置和长度,例如上述代码中span1.Slice(start: 1, length: 3)表示从span1中第2个元素开始包含3个元素的切片。

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
span1 contains the elements:6,23,76,88,
span2 contains the elements:23,76,88,

这里使用时一定注意传入参数 startlength 后的越界问题。

使用Span改变值

在文章开头,介绍了如何使用 Span<T> 的索引器,直接更改由 span 直接引用的数组元素,实际上它还有其他改变值的方法。

例如:

  • Slice(int start, int length):返回一个新的 Span<T>,它表示从 Span<T> 的指定起始位置开始的指定长度部分。可以使用该方法来获取或更改 Span<T> 中的子集。
  • Clear():将 Span<T> 中的所有元素设置为默认值 default<T>
  • Fill(T value):将 Span<T> 中的所有元素设置为指定的值。
  • CopyTo(Span<T> destination):将 Span<T> 中的所有元素复制到指定的目标 Span<T>
  • CopyTo(T[] destination):将 Span<T> 中的所有元素复制到指定的目标数组。
  • Reverse():反转 Span<T> 中的元素顺序。
  • Sort():对 Span<T> 中的元素进行排序。

请注意,这些方法都是按值传递的,而不是按引用传递的。这意味着在调用这些方法时,将复制 Span<T> 中的值。如果您想要修改原始 Span<T> 中的值,请使用引用传递方式,例如使用 ref Span<T> 参数。

只读的Span

如果只需要对数组片段进行读访问,则可以使用 ReadOnlySpan<T>,可以使用它来读取内存块中的数据,而不必担心其他代码同时修改了该内存块。

对于 ReadOnlySpan<T> ,它的索引器是只读的,所以这种类型没有提供 ClearFill 方法,但是可以调用 CopyTo() 方法,将 ReadOnlySpan<T> 的内容复制到 Span<T>

此外,它支持隐式转换,由数组或 Span<T> 直接赋值给 ReadOnlySpan<T>,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static void Main(string[] args)
{
    int[] source = { 1, 6, 23, 76, 88, 213 };

    Span<int> span = new Span<int>(source);

    DisplaySpan("span contains the elements:", span);

    ReadOnlySpan<int> readOnlySpan = source;

    DisplaySpan("readOnlySpan contains the elements:", readOnlySpan);

    Console.ReadLine();
}

private static void DisplaySpan(string content, ReadOnlySpan<int> span1)
{
    Console.Write(content);

    foreach (var item in span1)
    {
        Console.Write(item + ",");
    }

    Console.WriteLine();
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
span contains the elements:1,6,23,76,88,213,
readOnlySpan contains the elements:1,6,23,76,88,213,

Span<T> 相比,ReadOnlySpan<T> 的一个重要的限制是不允许修改其包含的内存块。这使得 ReadOnlySpan<T> 更适合于读取内存块中的数据,而不是修改它们。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-05-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Niuery Diary 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
数组(ArrayPool数组池、Span<T>结构)
  如果需要使用相同的类型的多个对象,就可以使用集合和数组,这一节主要讲解数组,其中会重点涉及到Span<T>结构和ArrayPool数组池。我们也会先涉及到简单的数组、多维数组、锯齿数组、Array类。
小世界的野孩子
2019/07/30
1.6K0
数组(ArrayPool数组池、Span<T>结构)
C#高性能开发之类型系统:从C# 7.0 到C# 14的类型系统演进全景
自C# 7.0以来,C#语言在类型系统方面引入了众多新数据类型、类型构造和语言特性,以提升性能、类型安全性和开发效率。本文全面整理了从C# 7.0到C# 14.0(截至2025年4月,C# 14.0为预览版)类型系统的新增内容,包括值元组、Span<T>、ReadOnlySpan<T>、Memory<T>、ReadOnlyMemory<T>、可空引用类型、记录、本机大小整数、记录结构、内联数组,以及其他增强(如只读结构、泛型数学支持)。
AI.NET 极客圈
2025/04/24
90
C#高性能开发之类型系统:从C# 7.0 到C# 14的类型系统演进全景
【C# 基础精讲】数组的创建与操作
数组是C#编程中非常重要的数据结构,它是一种用于存储相同类型元素的集合。通过数组,我们可以方便地访问和处理多个相关数据,这在很多编程场景下都是非常有用的。本文将详细介绍C#数组的创建与操作,包括数组的声明、初始化、访问元素、修改元素、获取数组长度、遍历数组以及使用多维数组等内容。
繁依Fanyi
2023/10/12
3490
【C# 基础精讲】数组的创建与操作
.Net Core中使用ref和Span<T>提高程序性能
其实说到ref,很多同学对它已经有所了解,ref是C# 7.0的一个语言特性,它为开发人员提供了返回本地变量引用和值引用的机制。 Span也是建立在ref语法基础上的一个复杂的数据类型,在文章的后半部分,我会有一个例子说明如何使用它。
yoyofx
2018/09/05
1.1K0
C# 经典排序算法大全
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/117527.html原文链接:https://javaforall.cn
全栈程序员站长
2022/07/05
6880
C# 经典排序算法大全
C#WinForm基础编程
视频课:https://edu.51cto.com/course/20906.html
张哥编程
2024/12/13
1120
站在前人的肩膀上重新透视C# Span<T>数据结构
先谈一下我对Span的看法, Span是指向任意连续内存空间的类型安全、内存安全的视图,可操作的滑动窗口。
有态度的马甲
2022/08/23
3510
站在前人的肩膀上重新透视C# Span<T>数据结构
在 C# 中使用 Span<T> 和 Memory<T> 编写高性能代码
原文地址:https://www.codemag.com/Article/2207031/Writing-High-Performance-Code-Using-SpanT-and-MemoryT-in-C
痴者工良
2022/09/23
3.1K0
在 C# 中使用 Span<T> 和 Memory<T> 编写高性能代码
数据结构与算法之二 排序
  假定,你要为你的生日聚会邀请你的朋友和亲戚。对此,你需要给他们打电话。你正在拥有10,000条记录的电话本中查找名为Steve的电话号码。然而,电话本中的记录是以随意顺序存储的。要在这样一个目录中查找你朋友的电话号码,你需要按顺序在目录中浏览每个条目。这将非常耗时,你如何解决此问题呢?
张哥编程
2024/12/17
1240
数据结构与算法之四 搜索算法
线性搜索: 是最简单的搜索方法, 也称作顺序搜索, 包括将用该条目逐一与列表中的条目进行比较, 线性搜索通过比较所需的元素与列表中第一个元素进行。
张哥编程
2024/12/17
860
C# 12 新增功能实操!
集合表达式引入了一种新的简洁语法,用于创建常用集合值。可以使用展开运算符(..)将其他集合内联到这些值中。
追逐时光者
2024/07/25
1390
C# 12 新增功能实操!
数据结构与算法之五 链接列表
假定您已经编写了一个算法来 ​产生并存储​ 1 到 10,00,000 之间的所有质数,然 后显示它们。 您如何解决这个问题? 考虑以下使用数组来解决此问题的算法: 1. Set I = 0 2. Repeat step 3 varying N from 2 to 1000000 3. If N is a prime number a. Set A[I] = N b. I = I + 1 4. Repeat step 5 varying J from 0 to I-1 5. Display A[J]
张哥编程
2024/12/17
620
数据结构与算法之三 深入学习排序
在本章中,你将学习: 通过使用快速排序来排序数据 通过使用归并排序来排序数据 快速排序算法 : 快速排序是最有效率的排序算法之一,此算法基于 分治法​连续 将问题​细分为更小的问题 ,​直到 问题​成为可以直接解决的小问题 在快速排序算法中,你: 从名为​枢轴 的列表处选择元素 。 将列表划分为两部分 : 列表左端的所有元素​小于等于 枢轴 。 列表右端的所有元素​大于 枢轴 。 在此列表两部分的​正确位置 存储​枢轴 。 划分之后为创建的​两个子列表重复​此过程 ( 找枢轴的过程 ) 。 直到 每个子列表中只剩一个元素 。 思想:就是不断找出符合条件的枢轴位置
张哥编程
2024/12/17
1170
C#基础搜索算法
大家好,我是苏州程序大白。下面讲讲C#中基础搜索算法。 数据搜索是基础的计算机编程工作, 而且人们对它的研究已经很多年了. 本章只会看到搜索问题的一个内容, 即根据给定的数值在一个列表(数组)中进行搜索. 有两种对列表内数据进行搜索的方法:顺序搜索和二叉搜索. 当数据项在列表内随机排列的时候可以使用顺序搜索, 而当数据项在列表内有序排列的时候则会用到二叉搜索。
苏州程序大白
2021/08/13
1K0
C#基础搜索算法
雷潮教育第一期班C#课程阶段总结(1)
1.基本数据类型 数值类型 整型 int 单精度浮点型 float 双精度浮点型 double 更高精度数值(财务) decimal 非数值类型 字符 char bool 字符串 string
孙寅
2020/06/02
6040
数据结构与算法之六 双向链表和循环链表
现在,考虑一个示例,您需要以降序的方式显示这些数字。 如何解决此问题? 每一个节点链接到序列中的下一个节点,这意味着您只能以正向遍历列表,这样的链接列表称为单链接列表。要以降序的方式显示数字,您需要反转此链接列表。 运用算法以反转单链接列表。
张哥编程
2024/12/17
1240
C#学习笔记——Queue队列
System.Collections.Queue类表示对象的先进先出集合,存储在 Queue(队列) 中的对象在一端插入,从另一端移除。
vv彭
2021/04/13
1.5K0
小白都能明白的构建字典中两大类
字典是一种把数据作为键值对(key-value pair)来存储的数据结构. 作为一种抽象的类, DictionaryBase类可以用来实现不同的数据结构, 其中这些数据结构全部把数据存储成键值对. 这些数据结构可能是哈希表, 链表或者其他一些数据结构类型. 本章节会讨论如何创建基础字典, 以及如何使用DictionaryBase类的继承方法. 稍后当研究更加专有的数据结构的时候将会用到这些技术。
苏州程序大白
2021/08/13
7060
小白都能明白的构建字典中两大类
C# Span & Memory
Span是.NET中引入的一种重要数据结构,它允许直接操作内存而无需复制数据。它指向连续内存空间,支持托管堆、原生内存和堆栈。Span是类型安全的泛型结构,提供了高性能的内存操作方式。它的引入解决了在处理大数据量时产生的性能和内存开销问题。Span可以用于数组、字符串和任何实现IReadOnlyList<T>接口的对象。
JusterZhu
2023/10/06
4740
C# Span & Memory
C# .NET面试系列九:常见的算法
在斐波那契数列中,通常是第一个和第二个数是1,后续的每个数是前两个数之和。因此,第30个数可以通过递归或循环方式计算。
GoodTime
2024/03/11
1990
C# .NET面试系列九:常见的算法
相关推荐
数组(ArrayPool数组池、Span<T>结构)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验