对于原始类型(包括字节),使用System.Buffer.BlockCopy 而不是System.Array.Copy。它更快。
我使用 3 个每个 10 字节的数组在一个循环中对每个建议的方法进行计时,执行 100 万次。结果如下:
- 使用
System.Array.Copy 的新字节数组 - 0.2187556 秒
- 使用
System.Buffer.BlockCopy 的新字节数组 - 0.1406286 秒
- IEnumerable 使用 C# yield 运算符 - 0.0781270 秒
- IEnumerable 使用 LINQ 的 Concat - 0.0781270 秒
我将每个数组的大小增加到 100 个元素并重新运行测试:
- 使用
System.Array.Copy 的新字节数组 - 0.2812554 秒
- 使用
System.Buffer.BlockCopy 的新字节数组 - 0.2500048 秒
- IEnumerable 使用 C# yield 运算符 - 0.0625012 秒
- IEnumerable 使用 LINQ 的 Concat - 0.0781265 秒
我将每个数组的大小增加到 1000 个元素并重新运行测试:
- 使用
System.Array.Copy 的新字节数组 - 1.0781457 秒
- 使用
System.Buffer.BlockCopy 的新字节数组 - 1.0156445 秒
- IEnumerable 使用 C# yield 运算符 - 0.0625012 秒
- IEnumerable 使用 LINQ 的 Concat - 0.0781265 秒
最后,我将每个数组的大小增加到 100 万个元素并重新运行测试,每个循环只执行 4000 次:
- 使用
System.Array.Copy 的新字节数组 - 13.4533833 秒
- 使用
System.Buffer.BlockCopy 的新字节数组 - 13.1096267 秒
- IEnumerable 使用 C# yield 运算符 - 0 秒
- IEnumerable 使用 LINQ 的 Concat - 0 秒
所以,如果你需要一个新的字节数组,使用
byte[] rv = new byte[a1.Length + a2.Length + a3.Length];
System.Buffer.BlockCopy(a1, 0, rv, 0, a1.Length);
System.Buffer.BlockCopy(a2, 0, rv, a1.Length, a2.Length);
System.Buffer.BlockCopy(a3, 0, rv, a1.Length + a2.Length, a3.Length);
但是,如果您可以使用 IEnumerable<byte>,肯定更喜欢 LINQ 的 Concat 方法。它只比 C# 的 yield 运算符慢一点,但更简洁、更优雅。
IEnumerable<byte> rv = a1.Concat(a2).Concat(a3);
如果您有任意数量的数组并且正在使用 .NET 3.5,您可以使 System.Buffer.BlockCopy 解决方案更通用,如下所示:
private byte[] Combine(params byte[][] arrays)
{
byte[] rv = new byte[arrays.Sum(a => a.Length)];
int offset = 0;
foreach (byte[] array in arrays) {
System.Buffer.BlockCopy(array, 0, rv, offset, array.Length);
offset += array.Length;
}
return rv;
}
*注意:上面的块需要你在顶部添加以下命名空间才能工作。
using System.Linq;
对于 Jon Skeet 关于后续数据结构(字节数组与 IEnumerable)的迭代的观点,我重新运行了最后的时序测试(100 万个元素,4000 次迭代),添加了一个循环来迭代整个每次传递的数组:
- 使用
System.Array.Copy 的新字节数组 - 78.20550510 秒
- 使用
System.Buffer.BlockCopy 的新字节数组 - 77.89261900 秒
- IEnumerable 使用 C# yield 运算符 - 551.7150161 秒
- IEnumerable 使用 LINQ 的 Concat - 448.1804799 秒
关键是,了解生成的数据结构的创建和使用的效率非常很重要。仅仅关注创造的效率可能会忽略与使用相关的低效率。致敬,乔恩。