c#比较字符串的最快方法

c#比较字符串的最快方法,c#,string,performance,C#,String,Performance,我注意到了 string1.Length == string2.Length && string1 == string2 在大字符串上比在 string1 == string2 这是真的吗?在比较实际字符串之前比较大字符串长度是否是一种好做法?或=内部调用string.Equals,因此使用框架提供的或=。它已经足够优化了 它首先比较引用,然后比较长度,然后比较实际字符 您可以找到源代码 代码:(来源:) 及 [System.Security.SecuritySafeCrit

我注意到了

string1.Length == string2.Length && string1 == string2
在大字符串上比在

string1 == string2
这是真的吗?在比较实际字符串之前比较大字符串长度是否是一种好做法?

=
内部调用
string.Equals
,因此使用框架提供的或
=
。它已经足够优化了

它首先比较引用,然后比较长度,然后比较实际字符

您可以找到源代码

代码:(来源:)

[System.Security.SecuritySafeCritical]//自动生成
[可靠性合同(Consistency.WillNotCorruptState,Cer.MayFail)]
专用不安全静态布尔EqualHelper(字符串strA、字符串strB)
{
合同要求(strA!=null);
Contract.Requires(strB!=null);
整数长度=直线长度;
if(length!=strB.length)返回false;
固定(char*ap=&strA.m_firstChar)固定(char*bp=&strB.m_firstChar)
{
char*a=ap;
char*b=bp;
//展开循环
#如果是AMD64
//对于AMD64位平台,我们以12和
//一次检查3个qword。这是更少的代码
//比32位的大小写短
//路径长度
while(长度>=12)
{
如果(*(长*)a!=*(长*)b)中断;
如果(*(长*)(a+4)!=*(长*)(b+4))中断;
如果(*(长*)(a+8)!=*(长*)(b+8))中断;
a+=12;b+=12;长度-=12;
}
#否则
而(长度>=10)
{
如果(*(int*)a!=*(int*)b)中断;
如果(*(int*)(a+2)!=*(int*)(b+2))中断;
如果(*(int*)(a+4)!=*(int*)(b+4))中断;
如果(*(int*)(a+6)!=*(int*)(b+6))中断;
如果(*(int*)(a+8)!=*(int*)(b+8))中断;
a+=10;b+=10;长度-=10;
}
#恩迪夫
//这取决于字符串对象是
//始终以零结束,且不包括终止零
//对于奇数字符串大小,最后一次比较将包括
//零终结者。
而(长度>0)
{
如果(*(int*)a!=*(int*)b)中断;
a+=2;b+=2;长度-=2;
}

返回(长度我想说第一个更快是因为
string1.length==string2.length
为false。由于短路评估(SCE),因此不会进行字符串之间的实际比较,这可能会节省您的时间

但是,如果字符串相等,则第一个字符串速度较慢,因为它将首先检查长度,然后执行与第二个字符串相同的操作


有关终止字符串中的
&&
运算符和SCE的信息,请参阅。

,只开始比较字符是有意义的,因为在不迭代所有字符的情况下无法计算字符串长度,比较可能会提前退出

对于长度计数字符串,如果要测试字节相等性,则应首先比较长度。。如果不检索长度,甚至无法开始访问字符数据,因为长度可能为零

如果您正在进行关系比较,知道长度不同并不能告诉您结果应该是正的还是负的。在区域性感知比较中,相等的字符串并不意味着长度相等。因此,对于这两种情况,您只需比较数据即可


If
运算符==(字符串,字符串)
简单地委托给关系比较,您不会期望比较长度。因此,在进行比较之前检查长度可能是一个好处。但框架似乎是从长度检查开始的。

string
s操作符equals在比较字符之前进行长度检查。因此,您不会保存使用此技巧对内容进行比较。由于长度检查假定字符串不为空,而BCL必须进行检查,因此您可能仍会节省一些CPU周期。因此,如果大部分时间长度不相等,您将短路一些指令

不过,我可能在这里错了。也许操作员内联了,检查也优化了。谁知道呢?(他测量了。)


如果您关心保存每个周期,那么首先可能应该使用不同的策略。也许托管代码甚至不是正确的选择。鉴于此,我建议使用较短的形式,而不使用附加检查。

根据ILSpy,字符串
==
运算符定义为:

public static bool operator ==(string a, string b)
{
    return string.Equals(a, b);
}
定义为

public static bool Equals(string a, string b)
{
    return a == b || (a != null && b != null && a.Length == b.Length && string.EqualsHelper(a, b));
}
我假设第一个
a==b
实际上是一个引用等式检查(ILSpy只是将其呈现为
=
),否则这将是一个无限递归的方法


这意味着
==
在实际比较字符串之前已经检查了字符串的长度。

因此,正如我承诺的那样,我用秒表编写了一个简短的代码-您可以复制粘贴它,然后在不同的字符串上尝试并查看差异

class Program
{
    static void Main(string[] args)
    {
        string str1 = "put the first value";
        string str2 = "put the second value";
        CompareTwoStringsWithStopWatch(str1, str2); //Print the results.
    }

    private static void CompareTwoStringsWithStopWatch(string str1, string str2)
    {
        Stopwatch stopwatch = new Stopwatch();

        stopwatch.Start();
        for (int i = 0; i < 99999999; i++)
        {
            if (str1.Length == str2.Length && str1 == str2)
            {
                SomeOperation();
            }
        }
        stopwatch.Stop();

        Console.WriteLine("{0}. Time: {1}", "Result for: str1.Length == str2.Length && str1 == str2", stopwatch.Elapsed);
        stopwatch.Reset();

        stopwatch.Start();
        for (int i = 0; i < 99999999; i++)
        {
            if (str1 == str2)
            {
                SomeOperation();
            }
        }
        stopwatch.Stop();

        Console.WriteLine("{0}. Time: {1}", "Result for: str1 == str2", stopwatch.Elapsed);
    }

    private static int SomeOperation()
    {
        var value = 500;
        value += 5;

        return value - 300;
    }
}
类程序
{
静态void Main(字符串[]参数)
{
string str1=“输入第一个值”;
string str2=“输入第二个值”;
CompareTowStringsWithStopWatch(str1,str2);//打印结果。
}
私有静态void comparetHostingsWithStopWatch(字符串str1、字符串str2)
{
秒表秒表=新秒表();
秒表。开始();
对于(int i=0;i<9999999;i++)
{
if(str1.Length==str2.Length&&str1==str2)
{
SomeOperation();
}
}
秒表;
WriteLine(“{0}.Time:{1}”,“结果为:str1.Length==str2.Length&&str1==str2”,stopwatch.appeased);
秒表复位();
秒表。开始();
对于(int i=0;i<9999999;i++)
{
如果(str1==str2)
{
SomeOperation();
}
}
public static bool Equals(string a, string b)
{
    return a == b || (a != null && b != null && a.Length == b.Length && string.EqualsHelper(a, b));
}
class Program
{
    static void Main(string[] args)
    {
        string str1 = "put the first value";
        string str2 = "put the second value";
        CompareTwoStringsWithStopWatch(str1, str2); //Print the results.
    }

    private static void CompareTwoStringsWithStopWatch(string str1, string str2)
    {
        Stopwatch stopwatch = new Stopwatch();

        stopwatch.Start();
        for (int i = 0; i < 99999999; i++)
        {
            if (str1.Length == str2.Length && str1 == str2)
            {
                SomeOperation();
            }
        }
        stopwatch.Stop();

        Console.WriteLine("{0}. Time: {1}", "Result for: str1.Length == str2.Length && str1 == str2", stopwatch.Elapsed);
        stopwatch.Reset();

        stopwatch.Start();
        for (int i = 0; i < 99999999; i++)
        {
            if (str1 == str2)
            {
                SomeOperation();
            }
        }
        stopwatch.Stop();

        Console.WriteLine("{0}. Time: {1}", "Result for: str1 == str2", stopwatch.Elapsed);
    }

    private static int SomeOperation()
    {
        var value = 500;
        value += 5;

        return value - 300;
    }
}
if (str1.Length == str2.Length)
{
    if (string.Compare(str1, str2, StringComparison.Ordinal) == 0)
    {
       doSomething()
    }
}
if (string.CompareOrdinal(stringsWeWantToSeeIfMatches[x], stringsWeAreComparingAgainst[x]) == 0)
{
//they're equal
}