【问题标题】:Does the order of appearance matter in a single IF statement with multiple conditions在具有多个条件的单个 IF 语句中出现的顺序是否重要
【发布时间】:2013-10-23 18:08:40
【问题描述】:

我有一个集合,其中包含 多达 19,000 个条目,我正在 foreach 语句中对其进行迭代。在 foreach 开始时,我检查一个字符串是否包含 2 个单词中的 1 个和一个布尔值,然后我继续或执行更多操作。

        foreach (SvnStatusEventArgs e in results) //results being my Collection
        {
            if ((e.Path.Contains("bin") || 
                e.Path.Contains("obj")) && !includeBinObjFolders)
                continue;

            //Do a bunch of things
        }

我不确定计算机是否会检查字符串中的“bin”或“obj”,然后检查布尔值,也许它会意识到字符串包含这两个 ' 之一并不重要关键词”。

基本上我猜我要说的是以下运行时间会不同吗?

        foreach (SvnStatusEventArgs e in results) //results being my Collection
        {
            if (!includeBinObjFolders && 
                    (e.Path.Contains("bin") || 
                     e.Path.Contains("obj")
                     )
                )
                continue;

            //Do a bunch of things
        }

出于某种原因,我听到脑后有个声音告诉我,它首先计算最右边的表达式,然后向左运行。如果是这样,第一个应该更有效率吧?我没有一种简单的方法来测试大于约 200 个文件的集合,所以简单地使用计时器会产生非常接近的结果,我无法确认是否有更好的方法。

坦率地说,我认为最终用户在这个集合中遇到超过 500 条数据的可能性极小,但理论上这可能是由于用户错误而发生的。

编辑谢谢大家。我在发帖之前尝试四处搜索,但我忘记了与逻辑有关的“短路”一词,所以我很难在这里找到与我冗长的标题相关的答案。

编辑 2 实际上,我刚刚创建了一个小型控制台应用程序,其中有 2 个 for 循环,每个循环迭代 20,000 次。一个首先测试 Contains,另一个首先测试 Bool。重复这两个循环 10 次,看起来布尔值第一次平均每 20K 次迭代需要半毫秒。首先评估的包含每 20K 次迭代大约需要 3 毫秒。确实有一点不同!

【问题讨论】:

  • 我想您想阅读有关“短路评估”的内容。比如这里:msdn.microsoft.com/en-us/library/2a723cdk.aspx
  • This question 应该回答你的问题。在您的第二个示例中,如果 !includeBinObjFolders = false 它停止
  • 在使用&& 时,您的评估会短路。在使用 || 时,您是说如果条件 1 评估 true,则不要评估条件 2。
  • 除了其他答案,我只想告诉你,你应该使用string.IndexOf——它比Contains快。然后,这是您的应用程序,您知道哪种情况发生最多。并且您的代码应该针对这种情况进行剪切,因此它大部分时间都会快速退出。
  • @T.S.进行了第二次编辑测试各种条件并记下结果。我还尝试比较 IndexOf 与 Contains 和 Contains 似乎最多快 2 毫秒,最坏的时间相同

标签: c# .net winforms performance


【解决方案1】:

最后一个表达式可能会在运行时为您节省更多,因为您只是先计算一个布尔值。如果那是假的,最右边的表达式甚至不会被评估,因为假 AND 任何东西都会是假的。

【讨论】:

    【解决方案2】:

    给定的布尔表达式将从左到右进行计算,而不是从右到左。顺序确实是定义的;它不是任意的,也不能被优化。它总是从左到右。

    规范中特别提到了这一点,以便每个表达式的副作用始终按定义的顺序执行。

    如果需要,您可以将布尔变量移到前面作为优化。它可能不是一个巨大的优化,所以不要太担心它,但它是一个优化。 (当然,除非您知道它将始终或几乎始终解析为 true,而另一个表达式将解析为 false。)

    【讨论】:

    • 太好了,谢谢!我不确定我是如何或为什么将它倒退的。不幸的是,我不确定布尔值在使用时是否更有可能为真。
    • 我会先进行布尔检查@sab669,因为这比首先比较字符串便宜得多
    【解决方案3】:

    逻辑运算符从左到右处理,&&|| 是短路运算符;意义

    x || y // will evaluate x and if it's false, then it will evaluate y
    x && y // will evaluate x and if it's true, then it will evaluate y
    

    http://msdn.microsoft.com/en-us/library/aa691310(v=vs.71).aspx

    你的第二种方法会更快

    【讨论】:

    • 实际上不仅仅是逻辑运算符,所有二元运算符都是从左到右计算的。
    【解决方案4】:

    在本例中,您是short-circuiting,您使用&&进行评估:

    foreach (SvnStatusEventArgs e in results) //results being my Collection
    {
       if (!includeBinObjFolders && 
          (e.Path.Contains("bin") || 
           e.Path.Contains("obj")))
           continue;
    
       //Do a bunch of things
    }
    

    所以基本上,如果!includeBinObjFolders = true 停止评估。

    在本例中,您使用|| 来评估前两个条件;如果其中一个true,您将停止评估。

    foreach (SvnStatusEventArgs e in results) //results being my Collection
    {
       if ((e.Path.Contains("bin") || 
          e.Path.Contains("obj")) && !includeBinObjFolders)
          continue;
    
          //Do a bunch of things
    }
    

    老实说,我认为任何一个都不会明显比另一个快。哦,顺便说一句,评估是从左到右的,而不是从右到左的。

    【讨论】:

    • 这里的要点是,如果您的布尔表达式本身执行起来很耗时(即,如果字符串很大,搜索字符串可能需要一段时间,或者您可以执行数据库查询之类的操作来获取布尔值)然后它会很重要。
    • 通常我不会在乎性能到这种程度,但我想如果我可以避免四十 000 个 String.Contains 调用,那应该会快很多吗?
    猜你喜欢
    • 2016-12-13
    • 2014-10-20
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    • 2010-12-28
    相关资源
    最近更新 更多