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

时间:2013-10-17 20:18:57

标签: c# string performance

我注意到了

string1.Length == string2.Length && string1 == string2
大字符串上的

稍快
string1 == string2

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

9 个答案:

答案 0 :(得分:19)

string s运算符equals在比较字符之前进行长度检查。所以你不要用这个技巧保存内容的比较。您可能仍然会节省几个CPU周期,因为您的长度检查假定字符串不为空,而BCL必须检查它。因此,如果长度在大多数时间不相等,您将短路一些指令。

但是,我可能在这里错了。也许操作员内联并且检查优化了。谁知道肯定? (他测量的人。)

如果您关心保存每个周期,您可能应该首先使用不同的策略。也许托管代码甚至不是正确的选择。鉴于此,我建议使用较短的表格,而不是使用额外的支票。

答案 1 :(得分:11)

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

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

您可以找到源代码here

代码:(来源:http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/clr/src/BCL/System/String@cs/1305376/String@cs

// Determines whether two strings match.
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public override bool Equals(Object obj) {
    if (this == null)                        //this is necessary to guard against reverse-pinvokes and
        throw new NullReferenceException();  //other callers who do not use the callvirt instruction

    String str = obj as String;
    if (str == null)
        return false;

    if (Object.ReferenceEquals(this, obj))
        return true;

    return EqualsHelper(this, str);
}

[System.Security.SecuritySafeCritical]  // auto-generated
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private unsafe static bool EqualsHelper(String strA, String strB)
{
    Contract.Requires(strA != null);
    Contract.Requires(strB != null);
    int length = strA.Length;
    if (length != strB.Length) return false;

    fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
    {
        char* a = ap;
        char* b = bp;

        // unroll the loop
#if AMD64
        // for AMD64 bit platform we unroll by 12 and
        // check 3 qword at a time. This is less code
        // than the 32 bit case and is shorter
        // pathlength

        while (length >= 12)
        {
            if (*(long*)a     != *(long*)b) break;
            if (*(long*)(a+4) != *(long*)(b+4)) break;
            if (*(long*)(a+8) != *(long*)(b+8)) break;
            a += 12; b += 12; length -= 12;
        }
 #else
        while (length >= 10)
        {
            if (*(int*)a != *(int*)b) break;
            if (*(int*)(a+2) != *(int*)(b+2)) break;
            if (*(int*)(a+4) != *(int*)(b+4)) break;
            if (*(int*)(a+6) != *(int*)(b+6)) break;
            if (*(int*)(a+8) != *(int*)(b+8)) break;
            a += 10; b += 10; length -= 10;
        }
  #endif

        // This depends on the fact that the String objects are
        // always zero terminated and that the terminating zero is not included
        // in the length. For odd string sizes, the last compare will include
        // the zero terminator.
        while (length > 0)
        {
            if (*(int*)a != *(int*)b) break;
            a += 2; b += 2; length -= 2;
        }

        return (length <= 0);
    }
}

答案 2 :(得分:7)

我的测试结果

将10000个字符串与10000个其他字符串进行比较,长度相同(256)

时间(s1 == s2):32536889滴答

时间(s1.Length == s2.Length)&amp;&amp; (s1 == s2):37380529 ticks

将10000个字符串与10000个其他字符串进行比较随机长度最大256

时间(s1 == s2):27223517滴答

时间(s1.Length == s2.Length)&amp;&amp; (s1 == s2):23419529 ticks

将10000个字符串与10000个其他字符串进行比较随机长度min 256 max 512

时间(s1 == s2):28904898蜱

时间(s1.Length == s2.Length)&amp;&amp; (s1 == s2):25442710滴答

我觉得令人难以置信的是,比较10000个相等长度的字符串需要比比较相同数量的更大数据的时间更长。

所有这些测试都是用完全相同的数据完成的。

答案 3 :(得分:4)

根据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只是将它呈现为==),否则这将是一个无限递归的方法。

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

答案 4 :(得分:3)

在终止字符串中,只是开始比较字符是有意义的,因为无论如何不能迭代所有字符都无法计算字符串长度,并且比较很可能提前退出。

对于长度计数的字符串,首先应该比较长度,如果要测试字节相等,则。你甚至无法在不检索长度的情况下开始访问字符数据,因为一个可能是零长度。

如果您正在进行关系比较,知道长度不同并不能告诉您结果是正面还是负面。在文化意识的比较中,相等的字符串并不意味着相同的长度。因此,对于这两者,您只需比较数据。

如果operator==(string, string)只是委托进行关系比较,那么你不会期望比较长度。因此,在进行比较之前检查长度可能是一个好处。但似乎框架确实以长度检查开始。

答案 5 :(得分:1)

对于我们中间的极客,here's a page在基准numerous ways to compare strings方面表现出色。

简而言之,最快的方法似乎是CompareOrdinal:

if (string.CompareOrdinal(stringsWeWantToSeeIfMatches[x], stringsWeAreComparingAgainst[x]) == 0)
{
//they're equal
}

第二种最好的方法似乎是使用Dictionary或Hashset,并使用“key”作为要比较的字符串。

进行有趣的阅读。

答案 6 :(得分:0)

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

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

有关&&运算符和SCE的信息,请参阅http://msdn.microsoft.com/en-us/library/2a723cdk.aspx

答案 7 :(得分:0)

因为我承诺我用秒表写了一个短代码 - 你可以复制粘贴它并尝试不同的字符串并查看差异

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;
    }
}

我的结论:

  1. 当我查看一些字符串(短字符串和长字符串)时,我看到所有结果几乎相同。因此,第一个if(使用长度检查)在2/3中较慢。
  2. 你在Object类中有一个Equals方法,只需使用它:)
  3. 您可以尝试并向我们提供结果:)

答案 8 :(得分:0)

如果您希望大多数时间字符串的长度不同,您可以比较它们的长度 AND ,然后使用string.Compare比较字符串本身。通过这样做,我的性能提升了近50%:

if (str1.Length == str2.Length)
{
    if (string.Compare(str1, str2, StringComparison.Ordinal) == 0)
    {
       doSomething()
    }
}

在这种情况下,我希望字符串几乎一直不同,我认为str1.Lenght比比较实际字符串便宜。如果它们的大小相等,我会比较它们。

编辑:忘了我说的话。只需使用==即可开心。