C#:ToArray表现

时间:2011-07-19 16:13:38

标签: c# .net linq performance

背景:

我承认我并没有尝试对此进行基准测试,但我很好奇......

Enumerable.ToArray<T>(及其堂兄Enumerable.ToList<T>)的CPU /内存特征是什么?

由于IEnumerable没有预先通告它有多少元素,我(或许天真地)假设ToArray必须“猜测”一个初始数组大小,然后重新调整/重新分配数组如果第一次猜测看起来太小,那么如果第二次猜测看起来太小等那么又要再次调整它...这会产生比线性更差的性能。

我可以想象更好的方法涉及(混合)列表,但这仍然需要多个分配(虽然不是重新分配)和相当多的复制,尽管它可能是线性整体,尽管有开销。

问题:

幕后是否有任何“魔法”发生,这避免了重复调整大小的需要,并使ToArray在空间和时间上呈线性?

更一般地说,是否有关于BCL性能特征的“官方”文档?

3 个答案:

答案 0 :(得分:15)

没有魔力。如果需要,可以调整大小。

请注意,始终不是必需的。如果IEnumerable<T> .ToArray也实现了ICollection<T>,那么.Count属性用于预分配数组(使算法在空间和时间上呈线性关系。)如果但是,不会执行以下(粗略)代码:

    foreach (TElement current in source)
    {
        if (array == null)
        {
            array = new TElement[4];
        }
        else
        {
            if (array.Length == num)
            {
                // Doubling happens *here*
                TElement[] array2 = new TElement[checked(num * 2)];
                Array.Copy(array, 0, array2, 0, num);
                array = array2;
            }
        }
        array[num] = current;
        num++;
    }

注意阵列填充时加倍。

无论如何,除非您绝对需要,否则通常最好避免调用.ToArray().ToList()。在需要时直接询问查询通常是更好的选择。

答案 1 :(得分:7)

我使用.NET Reflector提取了.ToArray()方法后面的代码:

public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    Buffer<TSource> buffer = new Buffer<TSource>(source);
    return buffer.ToArray();
}

和Buffer.ToArray:

internal TElement[] ToArray()
{
    if (this.count == 0)
    {
        return new TElement[0];
    }
    if (this.items.Length == this.count)
    {
        return this.items;
    }
    TElement[] destinationArray = new TElement[this.count];
    Array.Copy(this.items, 0, destinationArray, 0, this.count);
    return destinationArray;
}

在Buffer构造函数中,它遍历所有元素以计算实数Count和Elements数组。

答案 2 :(得分:2)

IIRC,它使用倍增算法。

请记住,对于大多数类型,您需要存储的所有内容都是引用。这并不像你分配足够的内存来复制整个对象(除非你使用了很多结构...... tsk tsk)。

避免使用.ToArray()或.ToList()直到最后一刻仍然是个好主意。大多数情况下,您可以继续使用IEnumerable&lt; T&gt;一直到你运行foreach循环或将其分配给数据源。