.Net 7 String的Equals和StartWith性能优化

起因

上个月就看到有一个issue,是对字符串  str == ""(调用String.Equals方法)和 str.StartsWith('c')进行优化的.
  1. Add IsKnownConstant jit helper and optimize 'str == ""' with str.StartsWith('c') (#63734)

在JIT(即时编译器)上的代码改进,就不说了(主要是不懂,水平不够),只能说说在C#层次上的改进.
在.Net 7中String的equals和StartWith性能改进

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'))
                    {

                    }
                }
            }
        }
    }
}

测试结果:

在.Net 7中String的equals和StartWith优化,测试基准

通过BenchmarkDotNet进行性能基准测试,发现Equals性能提升明显,最低有1倍,最高将近5倍的性能提升,对于StartWith不知道测试的代码不对,还是因为StartWith只对首个字符判断,所以这里表现的不明显.

秋风 2022-02-19