包含比StartsWith更快?

hac*_*sid 30 .net c# string performance

一位顾问昨天来了,不知怎的,字符串的主题出现了.他提到他已经注意到,对于长度小于一定长度的字符串,Contains实际上比它更快StartsWith.我必须用自己的两只眼睛看到它,所以我写了一个小应用程序,当然,Contains更快!

这怎么可能?

DateTime start = DateTime.MinValue;
DateTime end = DateTime.MinValue;
string str = "Hello there";

start = DateTime.Now;
for (int i = 0; i < 10000000; i++)
{
    str.Contains("H");
}
end = DateTime.Now;
Console.WriteLine("{0}ms using Contains", end.Subtract(start).Milliseconds);

start = DateTime.Now;
for (int i = 0; i < 10000000; i++)
{
    str.StartsWith("H");
}
end = DateTime.Now;
Console.WriteLine("{0}ms using StartsWith", end.Subtract(start).Milliseconds);
Run Code Online (Sandbox Code Playgroud)

输出:

726ms using Contains 
865ms using StartsWith
Run Code Online (Sandbox Code Playgroud)

我也尝试过更长的琴弦!

Kel*_*sey 26

尝试使用StopWatch测量速度而不是DateTime检查.

秒表与使用System.DateTime.Now进行计时事件

我认为关键是以下重要部分加粗:

Contains:

此方法执行序数 (区分大小写和 文化不敏感)比较.

StartsWith:

此方法使用当前文化执行单词 (区分大小写和文化敏感)比较.

我认为关键是顺序比较,相当于:

序数排序根据字符串中每个Char对象的数值比较字符串.序数比较自动区分大小写,因为字符的小写和大写版本具有不同的代码点.但是,如果案例在您的应用程序中不重要,您可以指定忽略大小写的序数比较.这相当于使用不变文化将字符串转换为大写,然后对结果执行序数比较.

参考文献:

http://msdn.microsoft.com/en-us/library/system.string.aspx

http://msdn.microsoft.com/en-us/library/dy85x1sa.aspx

http://msdn.microsoft.com/en-us/library/baketfxw.aspx

使用Reflector,您可以看到两者的代码:

public bool Contains(string value)
{
    return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}

public bool StartsWith(string value, bool ignoreCase, CultureInfo culture)
{
    if (value == null)
    {
        throw new ArgumentNullException("value");
    }
    if (this == value)
    {
        return true;
    }
    CultureInfo info = (culture == null) ? CultureInfo.CurrentCulture : culture;
    return info.CompareInfo.IsPrefix(this, value,
        ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
}
Run Code Online (Sandbox Code Playgroud)

  • 是! 这是对的.正如Daniel在另一篇评论中指出的那样,将StringComparison.Ordinal传递给StartsWith会使StartsWith比Contains快得多.我只是尝试了它并使用StartsWith获得"使用包含154.548ms的748.3209ms" (9认同)

Mat*_*hen 24

我想到了.这是因为StartsWith文化敏感,而Contains不是.这固有意味着StartsWith必须做更多的工作.

FWIW,这是我在Mono上的结果,其中包含以下(更正)基准:

1988.7906ms using Contains
10174.1019ms using StartsWith
Run Code Online (Sandbox Code Playgroud)

我很高兴看到人们对MS的结果,但我的主要观点是正确完成(并假设类似的优化),我认为StartsWith必须更慢:

using System;
using System.Diagnostics;

public class ContainsStartsWith
{
    public static void Main()
    {
        string str = "Hello there";

        Stopwatch s = new Stopwatch();
        s.Start();
        for (int i = 0; i < 10000000; i++)
        {
            str.Contains("H");
        }
        s.Stop();
        Console.WriteLine("{0}ms using Contains", s.Elapsed.TotalMilliseconds);

        s.Reset();
        s.Start();
        for (int i = 0; i < 10000000; i++)
        {
            str.StartsWith("H");
        }
        s.Stop();
        Console.WriteLine("{0}ms using StartsWith", s.Elapsed.TotalMilliseconds);

    }
}
Run Code Online (Sandbox Code Playgroud)

  • StartsWith默认使用CurrentCulture,这意味着比较必须检查"æ"=="ae"之类的等式.包含不做那些昂贵的检查.将StringComparison.Ordinal传递给StartsWith,使其与Contains一样快. (9认同)
  • 真的很好猜测,但可能不是.他没有传递文化,这一行是在StartsWith的实现中:`CultureInfo info =(culture == null)?CultureInfo.CurrentCulture:culture;` (2认同)
  • @Marc Bollinger - 你所看到的就是StartsWith对文化敏感,这就是声明. (2认同)
  • 为什么Microsoft为不同的字符串方法选择不同的规则?真令人发狂! (2认同)

Zak*_*ley 9

StartsWithContains表现完全不同,当涉及到文化敏感问题.

特别是,StartsWith返回true并不意味着Contains返回true.只有当你真正知道自己在做什么时,才应该用另一个替换其中一个.

using System;

class Program
{
    static void Main()
    {
        var x = "A";
        var y = "A\u0640";

        Console.WriteLine(x.StartsWith(y)); // True
        Console.WriteLine(x.Contains(y)); // False
    }
}
Run Code Online (Sandbox Code Playgroud)