在.NET中,如何使用Span进行内存高效操作?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1215个文字,预计阅读时间需要5分钟。
.NET Core 2.1的重头戏就是性能,其中最重要的两个类就是Span和Memory。本文简要介绍这两个类的使用。
Span是一个新的值类型,它表示一段连续的内存区域。它可以用来提高性能,因为它避免了复制操作。
Memory是一个引用类型,它封装了Span,并提供了额外的功能,如修改内存内容。
Span和Memory都是表示连续内存区域的方式,但它们有以下几个区别:
1. Span是值类型,Memory是引用类型。
2.Span可以直接操作内存,Memory提供更多高级操作。
3.Span更轻量级,因为它不包含引用计数。
使用示例:
csharp
Span span=new Span(new int[] { 1, 2, 3, 4, 5 });Console.WriteLine(span[0]); // 输出 1Memory memory=new Memory(new int[] { 1, 2, 3, 4, 5 });Console.WriteLine(memory.Span[0]); // 输出 1
总结:Span和Memory是.NET Core 2.1中提高性能的关键类。它们可以用来表示连续的内存区域,并提供了灵活的操作方式。
.net core 2.1的重头戏就是性能,其中最重要的两个类就是span和memory,本文这里简单的介绍一下这两个类的使用。
什么是 Span<T>
Span<T> 是新一种新值类型。它表示一段连续的区域,它通常和数组关联,表示数组中的一部分内存。
var arr = new byte[10]; Span<byte> bytes = arr;
也可以取数组中的一部分:
var bytes = new Span<byte>(arr, 3, 5);
初一乍看,span<T>和ArraySegment<T>非常类似,但span更加强大得多,它不但能用于分离数组,还可以引用栈上的数据。
Span<byte> bytes = stackalloc byte[2];
也可以引用指针数据,
Span<byte> bytes; unsafe { bytes = new Span<byte>((byte*)ptr, 1); }
另外,span还支持 reinterpret_cast 的理念,即可以将 Span<byte> 强制转换为 Span<int>,配合MemoryMarshal类使用,span<T>大多数的时候都可以代替指针了。
除了功能更加强大外,span在bcl库中也得到了更多的支持,大多数支持数组的函数现在基本上都能直接支持span了,如:
var inputSpan = input.AsSpan(); int first = int.Parse(inputSpan.Slice(3, 5));
这个函数中,int.Parse函数就能直接支持span,并且由于不产生子字符串,比使用substring的方法性能更高。
另外,系统也支持数组类型到span的隐式转换,同时提供了AsSpan的显示扩展方法,方便将数组类型转换为span。
除了功能强大外,span的性能也是非常高的,对span的操作基本上和访问数组一样高,无需通过计算来确定指针开头及其起始偏移,因为"引用"字段本身已对两者进行了封装。相比之下,ArraySegment<T> 有单独的偏移字段,这就增加了索引编制和数据传递操作的成本。
什么是 Memory<T>
Span<T>虽然强大而好用,但它只能存在于栈上,而不能存在于堆上,原因主要有如下两点:
- span包含"引用"字段(如数组的开头),这些引用被称为"内部指针"。对于 .NET 运行时的垃圾回收器,跟踪这些指针是一项成本相对高昂的操作。因此,运行时将这些引用约束为仅存在于堆栈上,因为它隐式规定了可以存在的内部指针数量下限。
- 对 Span 执行的读取和写入操作不是原子操作。如果多个线程同时对 Span 在堆上的字段执行读取和写入操作,存在"撕裂"风险。
这个限制决定了无法将 Span 装箱,进而无法将 Span<T> 与现有反射调用 API结合使用,也无法作为泛型参数。
对于大部分同步处理功能,这个并没有太大的影响,但由于span<T>无法存储到堆,从而导致其无法在异步上下文中使用。为了解决这个问题,.net引入了一个新类型Memory<T>。
Memory和span的使用方法大同小异,
var arr = new byte[10]; var bytes = new Memory<byte>(arr, 3, 5);
不同之处在于 Memory<T> 是不类似引用的结构,可以存在于堆上。.net bcl库对memory也做了很好的支持,如Stream.ReadAsync就能直接支持memory<byte>作为参数。
另外,也可以从Memory的Span属性创建指向该Memory的span,这样也可以使用span的强大的功能。
参考文章:
C# - Span 全面介绍:探索 .NET 新增的重要组成部分
到此这篇关于.net中Span<T>类和Memory<T>类的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持易盾网络。
本文共计1215个文字,预计阅读时间需要5分钟。
.NET Core 2.1的重头戏就是性能,其中最重要的两个类就是Span和Memory。本文简要介绍这两个类的使用。
Span是一个新的值类型,它表示一段连续的内存区域。它可以用来提高性能,因为它避免了复制操作。
Memory是一个引用类型,它封装了Span,并提供了额外的功能,如修改内存内容。
Span和Memory都是表示连续内存区域的方式,但它们有以下几个区别:
1. Span是值类型,Memory是引用类型。
2.Span可以直接操作内存,Memory提供更多高级操作。
3.Span更轻量级,因为它不包含引用计数。
使用示例:
csharp
Span span=new Span(new int[] { 1, 2, 3, 4, 5 });Console.WriteLine(span[0]); // 输出 1Memory memory=new Memory(new int[] { 1, 2, 3, 4, 5 });Console.WriteLine(memory.Span[0]); // 输出 1
总结:Span和Memory是.NET Core 2.1中提高性能的关键类。它们可以用来表示连续的内存区域,并提供了灵活的操作方式。
.net core 2.1的重头戏就是性能,其中最重要的两个类就是span和memory,本文这里简单的介绍一下这两个类的使用。
什么是 Span<T>
Span<T> 是新一种新值类型。它表示一段连续的区域,它通常和数组关联,表示数组中的一部分内存。
var arr = new byte[10]; Span<byte> bytes = arr;
也可以取数组中的一部分:
var bytes = new Span<byte>(arr, 3, 5);
初一乍看,span<T>和ArraySegment<T>非常类似,但span更加强大得多,它不但能用于分离数组,还可以引用栈上的数据。
Span<byte> bytes = stackalloc byte[2];
也可以引用指针数据,
Span<byte> bytes; unsafe { bytes = new Span<byte>((byte*)ptr, 1); }
另外,span还支持 reinterpret_cast 的理念,即可以将 Span<byte> 强制转换为 Span<int>,配合MemoryMarshal类使用,span<T>大多数的时候都可以代替指针了。
除了功能更加强大外,span在bcl库中也得到了更多的支持,大多数支持数组的函数现在基本上都能直接支持span了,如:
var inputSpan = input.AsSpan(); int first = int.Parse(inputSpan.Slice(3, 5));
这个函数中,int.Parse函数就能直接支持span,并且由于不产生子字符串,比使用substring的方法性能更高。
另外,系统也支持数组类型到span的隐式转换,同时提供了AsSpan的显示扩展方法,方便将数组类型转换为span。
除了功能强大外,span的性能也是非常高的,对span的操作基本上和访问数组一样高,无需通过计算来确定指针开头及其起始偏移,因为"引用"字段本身已对两者进行了封装。相比之下,ArraySegment<T> 有单独的偏移字段,这就增加了索引编制和数据传递操作的成本。
什么是 Memory<T>
Span<T>虽然强大而好用,但它只能存在于栈上,而不能存在于堆上,原因主要有如下两点:
- span包含"引用"字段(如数组的开头),这些引用被称为"内部指针"。对于 .NET 运行时的垃圾回收器,跟踪这些指针是一项成本相对高昂的操作。因此,运行时将这些引用约束为仅存在于堆栈上,因为它隐式规定了可以存在的内部指针数量下限。
- 对 Span 执行的读取和写入操作不是原子操作。如果多个线程同时对 Span 在堆上的字段执行读取和写入操作,存在"撕裂"风险。
这个限制决定了无法将 Span 装箱,进而无法将 Span<T> 与现有反射调用 API结合使用,也无法作为泛型参数。
对于大部分同步处理功能,这个并没有太大的影响,但由于span<T>无法存储到堆,从而导致其无法在异步上下文中使用。为了解决这个问题,.net引入了一个新类型Memory<T>。
Memory和span的使用方法大同小异,
var arr = new byte[10]; var bytes = new Memory<byte>(arr, 3, 5);
不同之处在于 Memory<T> 是不类似引用的结构,可以存在于堆上。.net bcl库对memory也做了很好的支持,如Stream.ReadAsync就能直接支持memory<byte>作为参数。
另外,也可以从Memory的Span属性创建指向该Memory的span,这样也可以使用span的强大的功能。
参考文章:
C# - Span 全面介绍:探索 .NET 新增的重要组成部分
到此这篇关于.net中Span<T>类和Memory<T>类的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持易盾网络。

