我使用一些使用Array.Copy 的测试将数组的部分复制到另一个。
第一个测试在值类型数组
上使用了Array.Copystruct ValueApple {
public int Redness;
}
ValueApple[] a1 = ...
ValueApple[] a2 = ...
Array.Copy(a1, a2, a1.Length);
然后第二个测试在引用类型数组
上使用了Array.Copyclass ReferenceApple {
public int Redness;
}
ReferenceApple[] a1 = ...
ReferenceApple[] a2 = ...
Array.Copy(a1, a2, a1.Length);
我来了,结果显示在值类型数组之间复制比在引用类型数组之间复制更快。
所以我的问题是:
这是真的吗?从一组值类型复制比从一组引用类型复制更快,为什么?
然后我的第二个问题是:
如果从值类型数组中复制更快。如果我为引用类型创建一个值类型的包装器,这不会帮助我提高性能吗?
例如
struct ValueWrapper<T> {
public T Value;
}
class ReferenceApple { }
ValueWrapper<ReferenceApple>[] a1 = new ValueWrapper<ReferenceApple>[20];
ValueWrapper<ReferenceApple>[] a2 = new ValueWrapper<ReferenceApple>[40];
Array.Copy(a1, a2, 20);
这还应该比使用普通的 ReferenceApple [] 数组快吗?
答案 0 :(得分:4)
ValueApple[]
vs ReferenceApple[]
;特定的差异很大程度上取决于目标平台;在x86上,它似乎在引用类型数组中有一些开销,但在x64上更不明显(它比 x86版本更快,尽管事实上{{1 }}版本现在正在复制两倍的数据):
86
ReferenceApple[]
64
ValueApple: 3295ms
ValueApple CopyTo: 3283ms
ReferenceApple: 4345ms
ReferenceApple CopyTo: 4234ms
我不会说这是值得折弯的代码。你还需要问:“阵列复制是我真正的瓶颈吗?”。如果不是,那么这个测试完全没有用。首先:找出你的瓶颈 是 。
某些情况下,struct-of-struct技巧可能会有所帮助,但通常与非常边缘情况高内存/垃圾更相关涉及长期巨大数据的收集方案。不是包含20/40项数组的常规代码。
以上数字基于:
ValueApple: 1819ms
ValueApple CopyTo: 1864ms
ReferenceApple: 2251ms
ReferenceApple CopyTo: 2335ms
for wrapped vs not:
我对你的结果提出质疑;我的数字:
using System;
using System.Diagnostics;
struct ValueApple
{
public int Redness;
}
class ReferenceApple
{
public int Redness;
}
static class Program {
static void Main()
{
const int LOOP = 50000000;
ValueApple[] a1 = new ValueApple[20];
ValueApple[] a2 = new ValueApple[40];
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
Array.Copy(a1, a2, 20);
}
watch.Stop();
Console.WriteLine("ValueApple: {0}ms", watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
a1.CopyTo(a2, 0);
}
watch.Stop();
Console.WriteLine("ValueApple CopyTo: {0}ms", watch.ElapsedMilliseconds);
ReferenceApple[] a3 = new ReferenceApple[20];
ReferenceApple[] a4 = new ReferenceApple[40];
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
Array.Copy(a3, a4, 20);
}
watch.Stop();
Console.WriteLine("ReferenceApple: {0}ms", watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
a3.CopyTo(a4, 0);
}
watch.Stop();
Console.WriteLine("ReferenceApple CopyTo: {0}ms", watch.ElapsedMilliseconds);
Console.WriteLine("(done)");
Console.ReadKey();
}
}
(最后一个版本是非通用版本)
基本上“大致相同,给予或采取随机CPU活动”。超过50M迭代的几毫秒肯定没有什么值得折弯的代码...
重要的是,确保所有此类测试都处于发布模式,并在调试器外部执行。
我的测试代码:
Wrapper<T>: 2175ms
Direct: 2231ms
Wrapper: 2165ms