首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在LINQ查询中调用ToList()或ToArray()更好吗?

在LINQ查询中调用ToList()或ToArray()更好吗?
EN

Stack Overflow用户
提问于 2009-07-09 19:28:55
回答 15查看 126.3K关注 0票数 596

我经常遇到这样的情况:我想在我声明查询的地方执行查询。这通常是因为我需要对它进行多次迭代,而且计算成本很高。例如:

代码语言:javascript
复制
string raw = "...";
var lines = (from l in raw.Split('\n')
             let ll = l.Trim()
             where !string.IsNullOrEmpty(ll)
             select ll).ToList();

这个很好用。但是,如果我不打算修改结果,那么我最好调用ToArray()而不是ToList()

然而,我想知道ToArray()是否是通过第一次调用ToList()实现的,因此,与调用ToList()相比,内存效率更低。

我疯了吗?我是否应该在知道内存不会被分配两次的情况下调用ToArray() -安全和安全?

EN

回答 15

Stack Overflow用户

回答已采纳

发布于 2013-05-01 17:42:23

除非您只需要一个数组来满足其他约束,否则您应该使用ToList。在大多数情况下,ToArray将分配比ToList更多的内存。

两者都使用数组作为存储,但是ToList有一个更灵活的约束。它需要数组至少与集合中的元素数一样大。如果数组更大,这不是问题。然而,ToArray需要数组的大小与元素的数量完全一致。

为了满足这一限制,ToArray通常比ToList多分配一次。一旦它有一个足够大的数组,它就会分配一个大小完全正确的数组,并将元素复制回该数组中。唯一可以避免这种情况的是,数组的grow算法恰好与需要存储的元素数(绝对是少数元素)相吻合。

编辑

有几个人问我,在List<T>值中拥有额外的未使用内存会带来什么后果。

这是一个值得关注的问题。如果创建的集合寿命很长,在创建后从未修改过,并且很有可能在Gen2堆中登陆,那么您最好先考虑ToArray的额外分配。

总的来说,我觉得这是比较少见的情况。更常见的是看到许多ToArray调用立即传递给其他短暂的内存使用,在这种情况下,ToList显然更好。

这里的关键是配置文件,配置文件,然后再配置更多。

票数 439
EN

Stack Overflow用户

发布于 2009-07-09 19:33:54

由于List<T>是作为一个动态大小的数组实现的,因此性能差异将是微不足道的。调用ToArray() (使用内部Buffer<T>类来增长数组)或调用ToList() (调用List<T>(IEnumerable<T>)构造函数)最终都需要将它们放入数组并扩展数组,直到它们全部满足。

如果您希望具体确认这一事实,请查看Reflector中所讨论的方法的实现--您将看到它们归结为几乎相同的代码。

票数 172
EN

Stack Overflow用户

发布于 2020-02-06 21:23:32

编辑2: (这是对原始答案的更正)

使用Benchmark.NET,我们可以通过性能度量来确认,接受的答案实际上是正确的:在一般情况下,ToList更快,因为它不需要从分配的缓冲区中修剪空空间。ToArray可能会执行额外的分配和复制操作,以使缓冲区的大小与元素的数量完全一致。

为了确认这一点,使用了以下基准测试。

代码语言:javascript
复制
[MemoryDiagnoser]
[ShortRunJob]
public class Benchmarks
{
    [Params(0, 1, 6, 10, 42, 100, 1337, 10000)]
    public int Count { get; set; }

    public IEnumerable<int> Items => Enumerable.Range(0, Count).Where(i => i > 0);

    [Benchmark(Baseline = true)]
    public int[] ToArray() => Items.ToArray();

    [Benchmark]
    public List<int> ToList() => Items.ToList();
}

结果证实,ToList在大多数情况下是10% - 15%的速度。

代码语言:javascript
复制
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
Intel Core i9-10885H CPU 2.40GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.302
  [Host]     : .NET 6.0.7 (6.0.722.32202), X64 RyuJIT
  DefaultJob : .NET 6.0.7 (6.0.722.32202), X64 RyuJIT


|  Method | Count |         Mean |      Error |     StdDev | Ratio | RatioSD |   Gen 0 |  Gen 1 | Allocated |
|-------- |------ |-------------:|-----------:|-----------:|------:|--------:|--------:|-------:|----------:|
| ToArray |     0 |     29.73 ns |   0.546 ns |   0.536 ns |  1.00 |    0.00 |  0.0067 |      - |      56 B |
|  ToList |     0 |     31.51 ns |   0.485 ns |   0.405 ns |  1.06 |    0.02 |  0.0105 |      - |      88 B |
|         |       |              |            |            |       |         |         |        |           |
| ToArray |     1 |     37.36 ns |   0.314 ns |   0.294 ns |  1.00 |    0.00 |  0.0114 |      - |      96 B |
|  ToList |     1 |     36.75 ns |   0.605 ns |   0.537 ns |  0.98 |    0.01 |  0.0153 |      - |     128 B |
|         |       |              |            |            |       |         |         |        |           |
| ToArray |     6 |    100.05 ns |   1.522 ns |   1.349 ns |  1.00 |    0.00 |  0.0286 |      - |     240 B |
|  ToList |     6 |     85.16 ns |   0.808 ns |   0.756 ns |  0.85 |    0.01 |  0.0267 |      - |     224 B |
|         |       |              |            |            |       |         |         |        |           |
| ToArray |    10 |    137.20 ns |   2.766 ns |   2.452 ns |  1.00 |    0.00 |  0.0372 |      - |     312 B |
|  ToList |    10 |    123.05 ns |   2.198 ns |   1.949 ns |  0.90 |    0.01 |  0.0372 |      - |     312 B |
|         |       |              |            |            |       |         |         |        |           |
| ToArray |    42 |    398.25 ns |   6.583 ns |   5.836 ns |  1.00 |    0.00 |  0.0877 |      - |     736 B |
|  ToList |    42 |    352.04 ns |   4.976 ns |   4.411 ns |  0.88 |    0.02 |  0.0887 |      - |     744 B |
|         |       |              |            |            |       |         |         |        |           |
| ToArray |   100 |    730.80 ns |   6.501 ns |   6.081 ns |  1.00 |    0.00 |  0.1488 |      - |   1,248 B |
|  ToList |   100 |    705.49 ns |   9.947 ns |   9.305 ns |  0.97 |    0.01 |  0.1526 |      - |   1,280 B |
|         |       |              |            |            |       |         |         |        |           |
| ToArray |  1337 |  8,023.57 ns | 147.388 ns | 137.867 ns |  1.00 |    0.00 |  1.6785 | 0.0458 |  14,056 B |
|  ToList |  1337 |  7,980.27 ns | 138.469 ns | 122.749 ns |  1.00 |    0.02 |  1.9989 | 0.1221 |  16,736 B |
|         |       |              |            |            |       |         |         |        |           |
| ToArray | 10000 | 57,037.19 ns | 510.492 ns | 452.538 ns |  1.00 |    0.00 | 12.6343 | 1.7700 | 106,280 B |
|  ToList | 10000 | 57,728.15 ns | 583.353 ns | 517.127 ns |  1.01 |    0.01 | 15.5640 | 5.1270 | 131,496 B |

作为参考,下面是原来的答案,不幸的是,它只在非常特殊的情况下执行了基准测试,避免了中间调整大小和复制操作。

原始答案:

现在是2020年,每个人都在使用.NET Core3.1,所以我决定使用Benchmark.NET运行一些基准测试。

TL;DR: ToArray()具有更好的性能,如果您不打算对集合进行变异,那么它可以更好地传达意图。

编辑:从注释中可以看出,这些基准可能不是指示性的,因为Enumerable.Range(...)返回一个包含序列大小信息的IEnumerable<T>,该信息随后被ToArray()用于优化,预先分配一个大小正确的数组。考虑手动测试性能,以确定确切的场景。

代码语言:javascript
复制
    [MemoryDiagnoser]
    public class Benchmarks
    {
        [Params(0, 1, 6, 10, 39, 100, 666, 1000, 1337, 10000)]
        public int Count { get; set; }
    
        public IEnumerable<int> Items => Enumerable.Range(0, Count);
    
        [Benchmark(Description = "ToArray()", Baseline = true)]
        public int[] ToArray() => Items.ToArray();
    
        [Benchmark(Description = "ToList()")]
        public List<int> ToList() => Items.ToList();
    
        public static void Main() => BenchmarkRunner.Run<Benchmarks>();
    }

研究结果如下:

代码语言:javascript
复制
    BenchmarkDotNet=v0.12.0, OS=Windows 10.0.14393.3443 (1607/AnniversaryUpdate/Redstone1)
    Intel Core i5-4460 CPU 3.20GHz (Haswell), 1 CPU, 4 logical and 4 physical cores
    Frequency=3124994 Hz, Resolution=320.0006 ns, Timer=TSC
    .NET Core SDK=3.1.100
      [Host]     : .NET Core 3.1.0 (CoreCLR 4.700.19.56402, CoreFX 4.700.19.56404), X64 RyuJIT
      DefaultJob : .NET Core 3.1.0 (CoreCLR 4.700.19.56402, CoreFX 4.700.19.56404), X64 RyuJIT
    
    
    |    Method | Count |          Mean |       Error |      StdDev |        Median | Ratio | RatioSD |   Gen 0 | Gen 1 | Gen 2 | Allocated |
    |---------- |------ |--------------:|------------:|------------:|--------------:|------:|--------:|--------:|------:|------:|----------:|
    | ToArray() |     0 |      7.357 ns |   0.2096 ns |   0.1960 ns |      7.323 ns |  1.00 |    0.00 |       - |     - |     - |         - |
    |  ToList() |     0 |     13.174 ns |   0.2094 ns |   0.1958 ns |     13.084 ns |  1.79 |    0.05 |  0.0102 |     - |     - |      32 B |
    |           |       |               |             |             |               |       |         |         |       |       |           |
    | ToArray() |     1 |     23.917 ns |   0.4999 ns |   0.4676 ns |     23.954 ns |  1.00 |    0.00 |  0.0229 |     - |     - |      72 B |
    |  ToList() |     1 |     33.867 ns |   0.7350 ns |   0.6876 ns |     34.013 ns |  1.42 |    0.04 |  0.0331 |     - |     - |     104 B |
    |           |       |               |             |             |               |       |         |         |       |       |           |
    | ToArray() |     6 |     28.242 ns |   0.5071 ns |   0.4234 ns |     28.196 ns |  1.00 |    0.00 |  0.0280 |     - |     - |      88 B |
    |  ToList() |     6 |     43.516 ns |   0.9448 ns |   1.1949 ns |     42.896 ns |  1.56 |    0.06 |  0.0382 |     - |     - |     120 B |
    |           |       |               |             |             |               |       |         |         |       |       |           |
    | ToArray() |    10 |     31.636 ns |   0.5408 ns |   0.4516 ns |     31.657 ns |  1.00 |    0.00 |  0.0331 |     - |     - |     104 B |
    |  ToList() |    10 |     53.870 ns |   1.2988 ns |   2.2403 ns |     53.415 ns |  1.77 |    0.07 |  0.0433 |     - |     - |     136 B |
    |           |       |               |             |             |               |       |         |         |       |       |           |
    | ToArray() |    39 |     58.896 ns |   0.9441 ns |   0.8369 ns |     58.548 ns |  1.00 |    0.00 |  0.0713 |     - |     - |     224 B |
    |  ToList() |    39 |    138.054 ns |   2.8185 ns |   3.2458 ns |    138.937 ns |  2.35 |    0.08 |  0.0815 |     - |     - |     256 B |
    |           |       |               |             |             |               |       |         |         |       |       |           |
    | ToArray() |   100 |    119.167 ns |   1.6195 ns |   1.4357 ns |    119.120 ns |  1.00 |    0.00 |  0.1478 |     - |     - |     464 B |
    |  ToList() |   100 |    274.053 ns |   5.1073 ns |   4.7774 ns |    272.242 ns |  2.30 |    0.06 |  0.1578 |     - |     - |     496 B |
    |           |       |               |             |             |               |       |         |         |       |       |           |
    | ToArray() |   666 |    569.920 ns |  11.4496 ns |  11.2450 ns |    571.647 ns |  1.00 |    0.00 |  0.8688 |     - |     - |    2728 B |
    |  ToList() |   666 |  1,621.752 ns |  17.1176 ns |  16.0118 ns |  1,623.566 ns |  2.85 |    0.05 |  0.8793 |     - |     - |    2760 B |
    |           |       |               |             |             |               |       |         |         |       |       |           |
    | ToArray() |  1000 |    796.705 ns |  16.7091 ns |  19.8910 ns |    796.610 ns |  1.00 |    0.00 |  1.2951 |     - |     - |    4064 B |
    |  ToList() |  1000 |  2,453.110 ns |  48.1121 ns |  65.8563 ns |  2,460.190 ns |  3.09 |    0.10 |  1.3046 |     - |     - |    4096 B |
    |           |       |               |             |             |               |       |         |         |       |       |           |
    | ToArray() |  1337 |  1,057.983 ns |  20.9810 ns |  41.4145 ns |  1,041.028 ns |  1.00 |    0.00 |  1.7223 |     - |     - |    5416 B |
    |  ToList() |  1337 |  3,217.550 ns |  62.3777 ns |  61.2633 ns |  3,203.928 ns |  2.98 |    0.13 |  1.7357 |     - |     - |    5448 B |
    |           |       |               |             |             |               |       |         |         |       |       |           |
    | ToArray() | 10000 |  7,309.844 ns | 160.0343 ns | 141.8662 ns |  7,279.387 ns |  1.00 |    0.00 | 12.6572 |     - |     - |   40064 B |
    |  ToList() | 10000 | 23,858.032 ns | 389.6592 ns | 364.4874 ns | 23,759.001 ns |  3.26 |    0.08 | 12.6343 |     - |     - |   40096 B |
    
    // * Hints *
    Outliers
      Benchmarks.ToArray(): Default -> 2 outliers were removed (35.20 ns, 35.29 ns)
      Benchmarks.ToArray(): Default -> 2 outliers were removed (38.51 ns, 38.88 ns)
      Benchmarks.ToList(): Default  -> 1 outlier  was  removed (64.69 ns)
      Benchmarks.ToArray(): Default -> 1 outlier  was  removed (67.02 ns)
      Benchmarks.ToArray(): Default -> 1 outlier  was  removed (130.08 ns)
      Benchmarks.ToArray(): Default -> 1 outlier  was  detected (541.82 ns)
      Benchmarks.ToArray(): Default -> 1 outlier  was  removed (7.82 us)
    
    // * Legends *
      Count     : Value of the 'Count' parameter
      Mean      : Arithmetic mean of all measurements
      Error     : Half of 99.9% confidence interval
      StdDev    : Standard deviation of all measurements
      Median    : Value separating the higher half of all measurements (50th percentile)
      Ratio     : Mean of the ratio distribution ([Current]/[Baseline])
      RatioSD   : Standard deviation of the ratio distribution ([Current]/[Baseline])
      Gen 0     : GC Generation 0 collects per 1000 operations
      Gen 1     : GC Generation 1 collects per 1000 operations
      Gen 2     : GC Generation 2 collects per 1000 operations
      Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
      1 ns      : 1 Nanosecond (0.000000001 sec)
票数 113
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1105990

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档