C#语法糖系列 —— 第四篇:聊聊 Span 的底层玩法
Posted dotNET跨平台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#语法糖系列 —— 第四篇:聊聊 Span 的底层玩法相关的知识,希望对你有一定的参考价值。
把 Span 归于语法糖,可能有些偏了,但偏了就偏了,哈哈,只要是分享就好,C# 发展至今,已经是一门非常重的语言了,所有想要的它都要,即可以:
面向过程编程
面向对象编程
面向函数式编程
面向异步编程
面向泛型编程
既能做到 高开发效率
,又能做到 高性能编程
。
这里的 Span
就归结于 高性能编程
这个范畴了。
一:Span 是什么
当年的 C# 一个亮点就是屏蔽了指针,自动内存托管,可以让程序员更加专注于业务,现如今策略变了,C# 要变得更加高性能,既然要做高性能那必然少不了指针
,而指针又是面向 托管层 编程的程序员最怕的东西,所以就尽可能的封装,弄一套属于自己的托管指针玩法。
Span
即属于托管指针玩法
的一个典型代表,如果你用 ILSpy 去看它的 struct
结构,本质上就两个成员,一个叫 _pointer
,一个叫 _length
,参考如下代码:
public readonly ref struct Span<T>
internal readonly ByReference<T> _pointer;
private readonly int _length;
pointer 是 指定起点, length 是 控制边界,如果用 C 来模拟,大概就是这个样子。
struct Span
void* ptr;
int length;
;
画个图大概就是这样子。
二:Span 的场景在哪里
有了指针,就可以对 内存
进行原地操作,只要能 原地操作
,那就可以破掉 语言层面
上的诸多限制,实现接近 C/C++
级的高性能,有些朋友可能要问了,语言层面有什么限制?比如最典型的 string
,大家都知道 string
是一个 writeoncopy
特性的字符串,只要你动它一下,它就会繁殖,接下来我们就拿 string
举个例子。
1. string 中的数字求 sum
在很久以前你可能会这么做。
static void Main(string[] args)
var s = "97 3";
var arr = s.Split(new string[] " " , StringSplitOptions.RemoveEmptyEntries);
var sum = Convert.ToInt32(arr[0]) + Convert.ToInt32(arr[1]);
Console.WriteLine(sum);
从代码可以看出,对 string 进行 Split
会导致生成多个小 string
对象,那有没有办法不用生成小string呢?这就需要用到托管版的 Span
做原地处理了。
static void Main(string[] args)
var s = "97 3";
var position = s.IndexOf(' ');
ReadOnlySpan<char> span = s.AsSpan();
var num1 = int.Parse(span.Slice(0, position));
var num2 = int.Parse(span.Slice(position));
Console.WriteLine(num1 + num2);
Span
的这种做法就是通过 _pointer
指针在内存地址上进行移动来完成,如果看不明白,我可以用 C
来模拟一下。
#include <iostream>
struct Span
int length;
void* ptr;
;
void sum(Span* span);
int main()
Span span;
span.ptr = (char*)"97 3";
span.length = strlen((char*)span.ptr);
sum(&span);
void sum(Span* span)
int sum = 0;
char* position = strchr((char*)span->ptr, ' ');
Span span1;
span1.ptr = span->ptr;
span1.length = (position - span->ptr) / sizeof(char);
Span span2;
span2.ptr = position;
span2.length = span->length - span1.length - 1;
int num1= atoi((char*)span1.ptr);
int num2= atoi((char*)span2.ptr);
sum = num1 + num2;
printf("sum=%d", sum);
虽然代码有点多,但逻辑还是很清楚的。
如果大家明白 Span
所封装的底层指针玩法,我想这其实没什么难的,本篇就说到这里吧,希望对你有帮助。
以上是关于C#语法糖系列 —— 第四篇:聊聊 Span 的底层玩法的主要内容,如果未能解决你的问题,请参考以下文章
C#语法糖系列 —— 第二篇:聊聊 ref,in 修饰符底层玩法
C#语法糖系列 —— 第一篇:聊聊 params 参数底层玩法
C#语法糖系列 —— 第二篇:聊聊 ref,in 修饰符底层玩法