【问题标题】:Find() vs. enumeration on listsFind() 与列表上的枚举
【发布时间】:2010-09-28 22:12:46
【问题描述】:

我正在使用一个代码库,其中需要经常搜索列表以查找单个元素。

使用 Predicate 和 Find() 是否比手动对 List 进行枚举更快?

例如:

string needle = "example";
FooObj result = _list.Find(delegate(FooObj foo) {
    return foo.Name == needle;
});

对比

string needle = "example";
foreach (FooObj foo in _list)
{
    if (foo.Name == needle)
        return foo;
}

虽然它们在功能上是相同的,但它们在性能上是否也相同?

【问题讨论】:

    标签: c# performance search list


    【解决方案1】:

    它们在性能上并不相同。 Find() 方法需要为列表中的每个项目调用一个方法(在本例中为委托)。与内联比较相比,方法调用不是免费的,而且相对成本很高。 foreach 版本不需要对每个对象进行额外的方法调用。

    话虽如此,在我真正分析我的代码并发现这是一个问题之前,我不会根据性能选择其中一个。我还没有发现这种场景的开销对于我编写的代码来说都是一个“热路径”问题,我在 Find 和其他类似方法中经常使用这种模式。

    【讨论】:

    • 您有数据支持您的声明吗?正如 dalle 所提到的,基准测试显示非常相似的代码相反。我看不出为什么编译器原则上不能内联 lambda,从而使这种方法至少与手动迭代一样有效。
    • @Konrad,我手头没有任何数据。但我们会定期在内部分析我们的代码,并且我会分析几个外部项目。在一个足够复杂的项目中,这从未接近瓶颈。它比较慢,但是一旦你在上面添加了一个真正的应用程序,它就不会被注意到了。
    • @Kronrad (cont) 编译器可以内联此代码,但目前 C# 编译器不会为优化目的对代码进行太多重写。 AFAIK,它永远不会内联 lambda。这当然是可能的。看F#。他们对代码进行了大量的重写。
    【解决方案2】:

    正如 Jared 指出的那样,存在差异。

    但是,与往常一样,除非您知道这是一个瓶颈,否则请不要担心。如果它是一个瓶颈,那可能是因为列表很大,在这种情况下,您应该考虑使用更快的查找 - 哈希表或二叉树,或者甚至只是对列表进行排序并进行二进制搜索会给您 log(n)这将比调整线性案例产生更大的影响。

    【讨论】:

      【解决方案3】:

      如果按原样搜索您的列表太慢,您可能会比线性搜索做得更好。如果可以保持列表排序,则可以使用二分查找在 O(lg n) 时间内找到元素。

      如果您要搜索一个全部批次,请考虑用字典替换该列表以按名称索引您的对象。

      【讨论】:

        【解决方案4】:

        从技术上讲,委托版本的运行时性能会比其他版本稍差 - 但在大多数情况下,您很难察觉到任何差异。

        更重要的 (IHMO) 是能够编写您想要的东西的代码时间性能,而不是您想要的方式。这对可维护性有很大影响。

        这个原始代码:

        string needle = "example";
        foreach (FooObj foo in _list)
        {
            if (foo.Name == needle)        
                return foo;
        }
        

        要求任何维护人员阅读代码并了解您正在寻找特定项目。

        这段代码

        string needle = "example";
        return _list.Find(
            delegate(FooObj foo) 
            {
                return foo.Name == needle;
            });
        

        明确表明您正在寻找特定项目 - 更容易理解。

        最后,这段代码使用了 C# 3.0 的特性:

        string needle = "example";
        return _list.Find( foo => foo.Name == needle);
        

        做完全相同的事情,但在一行中阅读和理解的速度更快(好吧,一旦你理解了lambda expressions,无论如何)。

        总而言之,鉴于替代方案的性能几乎相同,请选择一种使代码更易于阅读和维护的方案。

        【讨论】:

          【解决方案5】:

          “我正在使用一个代码库,其中列表需要经常搜索单个元素”

          最好将数据结构更改为 Dictionary 而不是 List 以获得更好的性能

          【讨论】:

            【解决方案6】:

            针对 List.ForEach 与 foreach-iteration (foreach vs someList.Foreach(){}) 提出了类似的问题。

            在这种情况下 List.ForEach 会快一些。

            【讨论】:

              猜你喜欢
              • 2018-08-13
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多