.Net 7 String的Equals和StartWith性能优化
起因
上个月就看到有一个issue,是对字符串 str == ""(调用String.Equals方法)和 str.StartsWith('c')进行优化的.- Add IsKnownConstant jit helper and optimize 'str == ""' with str.StartsWith('c') (#63734)
在JIT(即时编译器)上的代码改进,就不说了(主要是不懂,水平不够),只能说说在C#层次上的改进.

Equals和StartWith源码
public static bool Equals(string? a, string? b)
{
// Transform 'str == ""' to 'str != null && str.Length == 0' if either a or b are jit-time
// constants. Otherwise, these two blocks are eliminated
// 优化代码,调用运行时函数IsKnownConstant,如果字符串变量a在编译时是常量,IsKnownConstant就返回true
if (RuntimeHelpers.IsKnownConstant(a) && a != null && a.Length == 0)
{
return b != null && b.Length == 0;
}
if (RuntimeHelpers.IsKnownConstant(b) && b != null && b.Length == 0)
{
return a != null && a.Length == 0;
}
if (object.ReferenceEquals(a, b))
{
return true;
}
if (a is null || b is null || a.Length != b.Length)
{
return false;
}
return EqualsHelper(a, b);
}
public bool StartsWith(char value)
{
//增加运行时RuntimeHelpers.IsKnownConstant方法
if (RuntimeHelpers.IsKnownConstant(value) && value != '\0')
{
return _firstChar == value;
}
return Length != 0 && _firstChar == value;
}
看看运行时帮助方法IsKnownConstant:
[Intrinsic]
internal static bool IsKnownConstant(string? t) => false;
[Intrinsic]
internal static bool IsKnownConstant(char t) => false;
IsKnownConstant方法,在调用str==""代码时,JIT编译器判断str是不是常量,如果是常量返回true,不是常量返回false.
使用BenchmarkDotNet测试
namespace net6perf.StringFunction
{
[DisassemblyDiagnoser(printSource: true, maxDepth: 3)]
[MemoryDiagnoser]
public class StringEqualsTest
{
public char[] Chars = new char[52];
[Params("Hello", "")]
public string Content;
[Params(64, 128)]
public int Count;
[GlobalSetup]
public void Steup()
{
int index = 0;
for (int i = 65; i < 123; i++)
{
if (i > 90 && i < 97)
{
continue;
}
Chars[index] = (char)i;
index++;
}
}
[Benchmark]
public void EqualsTest()
{
for (int i = 0; i < Count; i++)
{
for (int j = 0; j < Chars.Length; j++)
{
if (Content == "")
{
}
}
}
}
[Benchmark]
public void StartWithTest()
{
for (int i = 0; i < Count; i++)
{
for (int j = 0; j < Chars.Length; j++)
{
if (Content.StartsWith('H'))
{
}
}
}
}
}
}
测试结果:
通过BenchmarkDotNet进行性能基准测试,发现Equals性能提升明显,最低有1倍,最高将近5倍的性能提升,对于StartWith不知道测试的代码不对,还是因为StartWith只对首个字符判断,所以这里表现的不明显.
秋风
2022-02-19