【问题标题】:Is the Lookup collection faster and more optimized than List of tuples in C#?查找集合是否比 C# 中的元组列表更快、更优化?
【发布时间】:2020-07-03 15:44:42
【问题描述】:

Lookup<string, string>List<(string, string)>?使用foreach 循环哪个更快?

如果您不需要搜索特定的键值对列表(键可能重复),使用元组的List 会更慢吗? Lookup 除了它的方法还有其他好处吗?

编辑:

非常聪明的评论提到了这一点,我应该将它添加到战斗中:

Lookup<string, string> vs List<(string, string)> vs Dictionary<string, List<string>>

【问题讨论】:

  • 他们真的很不一样。 Lookup<string, string> 更像是 Dictionary<string, List<string>> 而不是 List<(string, string)>
  • Race your horses。对于查找键的值,元素越多查找越快,元素越少线性搜索越快。 “更快”、“更多”和“更少”都取决于您的具体情况,这就是您需要进行剖析的原因。
  • 您能否举一个输入数据的示例,以及您是如何创建查找和列表的?
  • 您没有提到任何关于使用键作为键的内容,在这种情况下,将某些东西放入专为查找而设计的集合中是没有意义的键有效。
  • 你还没有解释过你是否真的在这个键上执行过任何查找,或者你是否从根本上你只想要一个项目序列。

标签: c# .net .net-core collections


【解决方案1】:

使用foreach 循环哪个更快?

要迭代,列表将快几个数量级。看看Lookup.GetEnumerator() 函数,看看它做了多少工作,因为它不会将原始元素存储在列表中:

   public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator() {
        Grouping g = lastGrouping;
        if (g != null) {
            do {
                g = g.next;
                yield return g;
            } while (g != lastGrouping);
        }
    }

我实际上坐下来为它写了一个基准:

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.17763.1282 (1809/October2018Update/Redstone5)
Intel Core i7-8850H CPU 2.60GHz (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=5.0.100-preview.4.20258.7
  [Host]     : .NET Core 3.1.4 (CoreCLR 4.700.20.20201, CoreFX 4.700.20.22101), X64 RyuJIT  [AttachedDebugger]
  DefaultJob : .NET Core 3.1.4 (CoreCLR 4.700.20.20201, CoreFX 4.700.20.22101), X64 RyuJIT


|     Method |      n |           Mean |        Error |       StdDev |    Gen 0 | Gen 1 | Gen 2 | Allocated |
|----------- |------- |---------------:|-------------:|-------------:|---------:|------:|------:|----------:|
| LookupTest |    100 |     2,733.6 ns |     25.08 ns |     22.23 ns |   0.8583 |     - |     - |    4048 B |
|   ListTest |    100 |       263.6 ns |      1.54 ns |      1.20 ns |        - |     - |     - |         - |
| LookupTest |   1000 |    27,185.6 ns |    245.01 ns |    217.20 ns |   8.4839 |     - |     - |   40048 B |
|   ListTest |   1000 |     2,306.6 ns |     22.53 ns |     19.97 ns |        - |     - |     - |         - |
| LookupTest |  10000 |   274,364.4 ns |  5,041.13 ns |  6,554.89 ns |  84.9609 |     - |     - |  400048 B |
|   ListTest |  10000 |    22,903.7 ns |    178.62 ns |    158.34 ns |        - |     - |     - |         - |
| LookupTest | 100000 | 2,774,880.1 ns | 49,165.10 ns | 58,527.55 ns | 847.6563 |     - |     - | 4000008 B |
|   ListTest | 100000 |   231,208.2 ns |  4,449.43 ns |  4,369.93 ns |        - |     - |     - |         - |

【讨论】:

  • 我不会那么肯定,除非没有分析。 JIT 可以做一些非常聪明的事情。
  • 您可以随心所欲地不确定,任何程序员都可以告诉您迭代连续的内存块与链表相比要快多少。
  • 我希望两者都足够快,以至于迭代列表的唯一时间是“快几个数量级”是如果你实际上没有对每个项目做任何事情 - 在这种情况下你完全不做可以让它无限快。
  • @JonSkeet 你们两个实际上让我怀疑自己,所以我为它写了一个快速基准,结果证实了我的直觉:超过一个数量级的差异。如果可以选择,永远不要使用链表!
  • 我认为我自己不会将“刚刚超过一个数量级”描述为“数量级”——我也不会说链表总是错误的选择。如果您希望能够在导航时删除或插入元素,它们会非常有用。但我认为更重要的是两者都真的可以快速迭代,如果您对每个项目都进行任何重要的工作,这可能会使迭代成本变得无关紧要。我认为这比“如果你有选择,你永远不应该使用链表”我自己更有价值和务实的一课。
猜你喜欢
  • 2011-08-03
  • 2019-07-07
  • 2012-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-14
相关资源
最近更新 更多