.NET Core 实战 [No.198] 使用 Span<T>
提升处理字符串的性能
Span<T>
用于操作各种 连续分布的内存数据 。可以通过以下来源初始化 Span<T>
:
常见的托管数组
csharpSpan<char> span = str.ToCharArray();
栈内存中的对象
csharpSpan<int> arr = stackalloc [] {1, 2, 3};
本地内存指针
csharp// 从进程的未托管内存中分配 100 字节的内存 IntPtr native = Marshal.AllocHGlobal(100); Span<byte> nativeSpan; unsafe { nativeSpan = new Span<byte>(native.ToPointer(), 100); }
Span<T>
支持 GC 功能,不需要显示释放内存。另外 ReadOnlySpan<T>
是其只读版本。
字符串的处理在 C# 和 Java 中都是类似的,每次字符串的修改都会创建一个新的实例,相当耗费资源。
这里通过一个示例,对比一下使用常规方法和使用 Span<T>
方法操作字符串时的性能。
示例功能:截取字符串中的字符 20 并转换为数值。
csharp
string str = "佳佳的博客 - 2020 - www.liujiajia.me";
Stopwatch sw1 = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
int v = int.Parse(str.Substring(9, 2));
}
sw1.Stop();
Console.WriteLine($"常规方法:耗时 {sw1.ElapsedMilliseconds} ms");
Stopwatch sw2 = Stopwatch.StartNew();
ReadOnlySpan<char> span = str.ToCharArray();
for (int i = 0; i < 10000000; i++)
{
int v = 0;
var subSpan = span.Slice(9, 2);
for (int j = 0; j < subSpan.Length; j++)
{
char ch = subSpan[j];
v = (ch - '0') + v * 10;
}
}
sw2.Stop();
Console.WriteLine($"使用 Span:耗时 {sw2.ElapsedMilliseconds} ms");
使用 str.Substring(9, 2)
方法截取字符串每次都会产生一个新的实例,而使用 span.Slice(9, 2)
则不会。
运行结果如下:
参考:《.NET Core 实战:手把手教你掌握 380 个精彩案例》 -- 周家安 著