【问题标题】:Copy array with `ToArray` Method使用 `ToArray` 方法复制数组
【发布时间】:2013-11-13 21:19:41
【问题描述】:

好吧,也许我只是懒惰,但这可能是互联网上的一个很酷的问题。

我知道Buffer.BlockCopy(...) 在使用byte[] 时比Array.Copy(...) 快。我正要编写一个 CloneBuffer 帮助器,它会创建一个与源数组大小相同的数组,然后使用 Buffer.BlockCopy(...) 将源数组复制到其中,但我却写道:

public void Send(byte[] data) {
    // Copy caller-provided buffer
    var buf = data.ToArray();

    // Start async send here and return immediately
}

有谁知道ToArray() 方法是否是byte[] 的特例,或者这是否会比BlockCopy 慢?

【问题讨论】:

  • 我会怀疑,但如果你好奇,你可以看看源代码,自己看看。
  • 你为什么觉得有必要把Buffer.BlockCopy放在首位?
  • @EdS。在我的代码的很多地方,我新建了一个新的byte[] 的源长度,然后将源复制到新数组中。它只是一个 DRY 函数,所以我不必在需要复制缓冲区的任何地方编写 3 行代码。

标签: c# performance linq


【解决方案1】:

您可以使用 反射器程序查看 Microsoft .NET 程序集,例如 ILSpy

这告诉我System.Linq.Enumerable::ToArray()的实现是:

public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)
{
    // ...
    return new Buffer<TSource>(source).ToArray();
}

而内部结构Buffer&lt;T&gt;的构造函数是:

  • 如果源可枚举实现ICollection&lt;T&gt;,则:
    • 分配一个由Count 元素组成的数组,并且
    • 使用CopyTo() 将集合复制到数组中。
  • 否则:
    • 分配一个包含 4 个元素的数组,并且
    • 开始枚举 IEnumerable,将每个值存储在数组中。
    • 阵列是否太小?
      • 创建一个大小是旧数组两倍的新数组,
      • 并将旧数组的内容复制到新数组中,
      • 然后改用新数组,然后继续。

如果Buffer&lt;T&gt;.ToArray() 的大小与其中的元素数量匹配,则仅返回内部数组;否则将内部数组复制到具有确切大小的新数组。

请注意,这个Buffer&lt;T&gt; 类是内部的,与您提到的Buffer 类无关。

所有的复制都是使用Array.Copy()完成的。

因此,总结一下:所有复制都是使用Array.Copy() 完成的,并且没有对字节数组进行优化。但是不知道是不是比Buffer.BlockCopy()慢。唯一知道的方法就是测量。

【讨论】:

  • 这很好,感谢您提供的信息。如果我记得,Array.Copy() 并没有那么慢很多,所以这可能满足我的需要。
【解决方案2】:

是的,它会变慢。

当您查看documentation for the System.Array methods 时,System.Array.ToArray() 没有定义。其实看继承/接口树,就是一路回溯到[IEnumerable.ToArray()][2]才找到这个方法。由于这是仅使用 IEnumerable 的功能来实现的,因此它在开始执行时无法知道结果数组的大小。相反,它使用加倍算法在运行时构建数组。因此,您最终可能会在制作副本的过程中创建并丢弃多个数组,并在销毁/重新创建每个中间缓冲区的过程中多次复制这些初始项目。

如果你想要一个更简单、幼稚的实现,至少看看Array.CopyTo()。请记住:我说的是“如果”。

【讨论】:

  • 这是不正确的。为什么你认为它只能用IEnumerable的特性来实现?如果可枚举实现ICollection&lt;T&gt;,它确实在开始执行时知道结果数组的大小。这是一种优化。
猜你喜欢
  • 2013-07-09
  • 2016-02-09
  • 1970-01-01
  • 2014-01-18
  • 1970-01-01
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
相关资源
最近更新 更多