【问题标题】:Is String.Contains() faster than String.IndexOf()?String.Contains() 是否比 String.IndexOf() 快?
【发布时间】:2009-01-31 11:42:36
【问题描述】:

我有一个大约 2000 个字符的字符串缓冲区,需要检查缓冲区是否包含特定字符串。
将为每个 web 请求在 ASP.NET 2.0 webapp 中进行检查。

有谁知道String.Contains method 的性能是否优于String.IndexOf method

    // 2000 characters in s1, search token in s2
    string s1 = "Many characters. The quick brown fox jumps over the lazy dog"; 
    string s2 = "fox";
    bool b;
    b = s1.Contains(s2);
    int i;
    i = s1.IndexOf(s2);

Fun fact

【问题讨论】:

  • 如果您需要为每个 Web 请求执行十亿次,我会开始研究类似的东西。在任何其他情况下,我都不会打扰,因为与最初接收 HTTP 请求相比,在这两种方法中花费的时间很可能微不足道。
  • 优化的关键之一是测试而不是假设,因为它可能取决于很多因素,例如 .NET 版本、操作系统、硬件、输入的变化等。其他人完成的许多案例测试结果在您​​的系统上可能会非常不同。

标签: c# .net asp.net performance string


【解决方案1】:

Contains 致电IndexOf

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

调用CompareInfo.IndexOf,最终使用CLR实现。

如果您想查看如何在 CLR this will show you 中比较字符串(查找 CaseInsensitiveCompHelper)。

IndexOf(string) 没有选项,Contains() 使用序数比较(逐字节比较,而不是尝试执行智能比较,例如,e 与 é)。

所以IndexOf 会稍微快一些(理论上),因为IndexOf 直接使用来自 kernel32.dll 的 FindNLSString 进行字符串搜索(反射器的强大功能!)。

为 .NET 4.0 更新 - IndexOf 不再使用序数比较,因此 Contains 可以更快。请参阅下面的评论。

【讨论】:

  • 这个答案远非正确,请看这里stackoverflow.com/posts/498880/revisions的解释
  • 我的答案是 7 岁,并且基于 .NET 2 框架。版本 4 IndexOf() 确实使用了 StringComparison.CurrentCultureContains() 使用 StringComparison.Ordinal 会更快。但实际上我们正在谈论的速度差异是微小的 - 关键是一个调用另一个,如果您不需要索引,包含更具可读性。换句话说,不用担心。
  • 今天在一个 1.3 GB 的文本文件上进行了尝试。除其他外,每行都会检查是否存在“@”字符。对 Contains/IndexOf 进行了 17.000.000 次调用。结果:所有 Contains() 调用需要 12.5 秒,所有 IndexOf() 调用需要 2.5 秒。 => IndexOf 执行速度快 5 倍!! (.Net 4.8)
  • @CSharper 你能分享一下这个基准测试的源代码吗?
【解决方案2】:

Contains(s2) 比 IndexOf(s2) 快很多倍(在我的计算机中是 10 倍),因为 Contains 使用 StringComparison.Ordinal,它比 IndexOf 默认执行的文化敏感搜索要快(但在 .net 中可能会发生变化4.0http://davesbox.com/archive/2008/11/12/breaking-changes-to-the-string-class.aspx)。

在我的测试中,Contains 与 IndexOf(s2,StringComparison.Ordinal) >= 0 具有完全相同的性能,但它更短,并且使您的意图更加明确。

【讨论】:

【解决方案3】:

我正在运行一个真实案例(与综合基准测试相反)

 if("=,<=,=>,<>,<,>,!=,==,".IndexOf(tmps)>=0) {

 if("=,<=,=>,<>,<,>,!=,==,".Contains(tmps)) {

它是我系统的重要组成部分,它被执行了 131,953 次(感谢 DotTrace)。

然而令人震惊的惊喜,结果却与预期相反

  • IndexOf 533 毫秒。
  • 包含 266 毫秒。

:-/

net framework 4.0(更新至 13-02-2012)

【讨论】:

  • 因为INTBOOL 大得多,而IndexOf&gt;=0 导致多了一步
  • 您忘记使用“StringComparison.Ordinal”
【解决方案4】:

使用 Reflector 可以看到,Contains 是使用 IndexOf 实现的。这是实现。

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

所以 Contains 可能比直接调用 IndexOf 慢一点,但我怀疑它对实际性能有什么意义。

【讨论】:

  • 是的,但是要将 indexof 用作布尔值,他必须在函数之外进行比较。这很可能会得到与包含相同的结果,不是吗?
  • 可能,但您确实保存了一个方法调用(除非它可以内联)。正如我所说,它可能永远不会很重要。
【解决方案5】:

如果您真的想对代码进行微优化,最好的方法始终是基准测试。

.net 框架具有出色的秒表实现 - System.Diagnostics.Stopwatch

【讨论】:

  • 这是最好的但是如果你想要一个快速的方法,只需在调试会话中按下暂停按钮。代码控制可能会在最慢的部分停止大约 50% 的时间
  • @JeremyThompson 重复“暂停调试”方法 10 次,你就得到了一个分析器
【解决方案6】:

从一些阅读中可以看出,String.Contains 方法在底层只是简单地调用了 String.IndexOf。不同之处在于 String.Contains 返回一个布尔值,而 String.IndexOf 返回一个整数,其中 (-1) 表示未找到子字符串。

我建议编写一个大约 100,000 次迭代的小测试,然后自己看看。如果我猜测,我会说 IndexOf 可能会稍微快一些,但就像我说的那样,这只是一个猜测。

Jeff Atwood 在his blog 上有一篇关于字符串的好文章。它更多地是关于连接,但仍然可能会有所帮助。

【讨论】:

    【解决方案7】:

    作为对此的更新,我一直在进行一些测试并提供您的输入字符串相当大,然后并行 Regex 是我发现的最快的 C# 方法(假设您有多个我想象的核心)

    例如获取匹配总数 -

    needles.AsParallel ( ).Sum ( l => Regex.IsMatch ( haystack , Regex.Escape ( l ) ) ? 1 : 0 );
    

    希望这会有所帮助!

    【讨论】:

    • 嗨,phild 在一个单独的线程中使用来自 tomasp.net/articles/ahocorasick.aspx 的版本更新了此内容,如果您的关键字(针)不更改,速度会快很多。
    【解决方案8】:

    使用基准库,例如 this recent foray from Jon Skeet 来衡量它。

    Caveat Emptor

    与所有(微)性能问题一样,这取决于您使用的软件版本、检查数据的详细信息以及调用周围的代码。

    作为所有(微)性能问题,第一步必须是获得易于维护的运行版本。然后可以将基准测试、分析和调整应用于测量的瓶颈,而不是猜测。

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。
    • 链接库只是众多库之一,而不是答案的主旨。我不认为发布库的来源或描述会改善答案、这个网站或世界。
    • -1 ;问题是“有谁知道 String.Contains 方法的性能是否优于 String.IndexOf 方法?” - 你的答案是“使用基准库”,这基本上意味着“我不知道,你自己做”,“这取决于”,这意味着“我不知道”,以及“获得一个正在运行的版本和配置文件” ,这也意味着“我不知道,自己做”。这不是“危险” - 请提供答案 对所提出的问题,而不是操作方法 想法 - 他们的位置在 cmets.
    【解决方案9】:

    今天在一个 1.3 GB 的文本文件上进行了尝试。除其他外,每行都会检查是否存在“@”字符。对 Contains/IndexOf 进行了 17.000.000 次调用。结果:所有 Contains('@') 调用需要 12.5 秒,所有 IndexOf('@') 调用需要 2.5 秒。 => IndexOf 执行速度快 5 倍!! (.Net 4.8)

    【讨论】:

      【解决方案10】:

      对于仍在阅读本文的任何人,indexOf() 在大多数企业系统上的性能可能会更好,因为 contains() 与 IE 不兼容!

      【讨论】:

      • 抛出新的 OutOfScopeException();
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-14
      • 2023-03-25
      相关资源
      最近更新 更多