在C#中如何减少新字符串的产生
前言
最近看到了一段代码,在工作中,也是这样的用法,这样的用法其实现在是不太好的.先看看这一段代码.public string HandlerActionName2(string actionName)
{
if (actionName.EndsWith("Async", StringComparison.Ordinal))
{
actionName = actionName.Substring(0, actionName.Length - 5); //这里用Substring真的合适不?
}
return actionName;
}
在调用HandlerActionName2的,如果还是会创建新新字符串,这里是不是就没必要产生的新字符串呢? 在.Net Core 2.1 提供了ReadOnlySpan用在这里是减少创建新字符串的.
public ReadOnlySpan<char> HandleActionName(ReadOnlySpan<char> actionName)
{
if (actionName.EndsWith("Async", StringComparison.Ordinal))
{
//使用ReadOnlySpan的Slice进行切片,这个没有产生新的字符串
actionName = actionName.Slice(0, actionName.Length - 5);
}
return actionName;
}
性能基准测试
测试代码:using System;
using BenchmarkDotNet.Attributes;
namespace CSharpBenchmarks.StringTest
{
[MemoryDiagnoser]
[DisassemblyDiagnoser(printSource: true)]
public class StringToReadOnlySpan
{
/// <summary>
/// 分别执行1024次和202048次
/// </summary>
[Params(1024, 2048)]
public int Times { get; set; }
/// <summary>
///这里有两个字符串,用于测试
/// </summary>
[Params("TestAsync", "Test")]
public string Names { get; set; }
[Benchmark]
public int ReadOnlySpanTest()
{
int count = 0;
for (int i = 0; i < Times; i++)
{
count += HandleActionName(Names).Length;
}
return count;
}
[Benchmark(Baseline = true)]
public int StringTest()
{
int count = 0;
for (int i = 0; i < Times; i++)
{
count += HandlerActionName2(Names).Length;
}
return count;
}
public ReadOnlySpan<char> HandleActionName(ReadOnlySpan<char> actionName)
{
if (actionName.EndsWith("Async", StringComparison.Ordinal))
{
//使用ReadOnlySpan的Slice进行切片,这个没有产生新的字符串
actionName = actionName.Slice(0, actionName.Length - 5);
}
return actionName;
}
public string HandlerActionName2(string actionName)
{
if (actionName.EndsWith("Async", StringComparison.Ordinal))
{
actionName = actionName.Substring(0, actionName.Length - 5); //这里用Substring真的合适不?
}
return actionName;
}
}
}
笔记本执行结果:
根据测试结果:
1. 如果字符串中没有Async结尾的话,使用String比ReadOnlySpan比快35%和100%之间,具体取决于硬件了.
2. 如果字符中是以Async结尾的话,ReadOnlySpan<char>的Slice只是String.SubString的25%和29%,换而言之,SubString比Slice耗时多了3倍,因为Slice是没有产生新字符串,这一点从GC 0代回收次数也可以看到.减少内存分配,降低出发GC回收的次数.
秋风
2024-12-29