C# 克隆交错数组比多维数组慢
我试图克隆一个大小约为100x100的多维数组,我找到的每一个资源似乎都表明使用交错数组应该更有效(至少在查找中,因为多维数组使用函数调用) 但我的问题是,我对这些数组进行了大量克隆,这似乎比只克隆multArray.Clone()要慢得多 示例代码:C# 克隆交错数组比多维数组慢,c#,.net,multidimensional-array,jagged-arrays,C#,.net,Multidimensional Array,Jagged Arrays,我试图克隆一个大小约为100x100的多维数组,我找到的每一个资源似乎都表明使用交错数组应该更有效(至少在查找中,因为多维数组使用函数调用) 但我的问题是,我对这些数组进行了大量克隆,这似乎比只克隆multArray.Clone()要慢得多 示例代码: class Program { static void Main(string[] args) { int matSize = 100; int iterat
class Program
{
static void Main(string[] args)
{
int matSize = 100;
int iterations = 100000;
Random r = new Random();
Stopwatch sw = new Stopwatch();
double[][] jaggedMat = new double[matSize][];
double[,] multiMat = new double[matSize, matSize];
for(int i = 0; i < matSize; i++)
{
jaggedMat[i] = new double[matSize];
for (int j = 0; j < matSize; j++)
{
double v = r.NextDouble();
jaggedMat[i][j] = v;
multiMat[i, j] = v;
}
}
Console.WriteLine($"Cloning jagged matrix old school.");
sw.Start();
for (int i=0; i<iterations; i++)
{
double[][] copy = new double[matSize][];
for(int j = 0; j <matSize; j++)
{
copy[j] = new double[matSize];
for (int k = 0; k < matSize; k++)
{
copy[j][k] = jaggedMat[j][k];
}
}
}
sw.Stop();
Console.WriteLine($"Cloning took {sw.ElapsedMilliseconds}ms");
Console.WriteLine($"Cloning using LINQ");
sw.Reset();
sw.Start();
for (int i = 0; i < iterations; i++)
{
var clone = jaggedMat.Select(element => element.ToArray()).ToArray();
}
sw.Stop();
Console.WriteLine($"Cloning took {sw.ElapsedMilliseconds}ms");
Console.WriteLine($"Cloning multidimensional array.");
sw.Reset();
sw.Start();
for(int i = 0; i < iterations; i++)
{
var clone = multiMat.Clone() as double[,];
}
sw.Stop();
Console.WriteLine($"Cloning took {sw.ElapsedMilliseconds}ms");
Console.ReadKey();
}
}
类程序
{
静态void Main(字符串[]参数)
{
int matSize=100;
int迭代次数=100000次;
随机r=新随机();
秒表sw=新秒表();
double[]jaggedMat=新的double[matSize][];
double[,]multiMat=新的double[matSize,matSize];
对于(int i=0;i 对于(int i=0;i我没有测量性能。但是您可以用更少的代码来解决这个问题。我的解决方案序列化和反序列化整个数组,以获得它的深度副本
using System.Runtime.Serialization.Formatters.Binary;
BinaryFormatter formatter = new BinaryFormatter();
using(var ms = new MemoryStream())
{
var array = new int[100, 100];
array [0, 1] = 57; // simple test data to validate the output.
formatter.Serialize(ms, array );
ms.Position = 0; // rewind the stream to deserialize it.
var copied = formatter.Deserialize(ms);
}
我没有衡量性能。但是你可以用更少的代码来解决这个问题。我的解决方案序列化和反序列化整个数组,以获得它的深层副本
using System.Runtime.Serialization.Formatters.Binary;
BinaryFormatter formatter = new BinaryFormatter();
using(var ms = new MemoryStream())
{
var array = new int[100, 100];
array [0, 1] = 57; // simple test data to validate the output.
formatter.Serialize(ms, array );
ms.Position = 0; // rewind the stream to deserialize it.
var copied = formatter.Deserialize(ms);
}
这样做:
double[][] copy = new double[matSize][];
for (int j = 0; j < matSize; j++)
{
copy[j] = jaggedMat[j].Clone() as double[];
}
double[]copy=new double[matSize][];
对于(int j=0;j
它只会使锯齿状数组比多维数组慢2倍(在我的机器上是2450ms对1360ms)。简单地说,创建100个对象(锯齿状数组的行)是有成本的。GC会有点讨厌你:-)如果GC运行,所有这些对象都必须被分配,然后被释放。这使得锯齿状数组的克隆速度变慢。我要说的是,成本如此之低是很有趣的(鉴于多维克隆是纯填充,而锯齿阵列克隆是半复制半创建阵列,因此创建阵列的成本似乎与填充阵列的成本相同)请执行以下操作:
double[][] copy = new double[matSize][];
for (int j = 0; j < matSize; j++)
{
copy[j] = jaggedMat[j].Clone() as double[];
}
double[]copy=new double[matSize][];
对于(int j=0;j
它只会使锯齿状数组比多维数组慢2倍(在我的机器上是2450ms对1360ms)。简单地说,创建100个对象(锯齿状数组的行)是有成本的。GC会有点讨厌你:-)如果GC运行,所有这些对象都必须被分配,然后被释放。这使得锯齿状数组的克隆速度变慢。我要说的是,成本如此之低是很有趣的(鉴于多维克隆是纯填充,而锯齿状数组克隆是半复制半创建数组,因此创建数组的成本似乎与填充数组的成本相同)我希望您是在发布模式下运行测试,并且没有调试器(CTRL+F5或直接在命令行中)…我经常在测试开始时添加一个Process.GetCurrentProcess().PriorityClass=ProcessPriorityClass.High;
,以提高程序运行期间的优先级。我会说克隆锯齿状数组应该更慢。请注意,可以半克隆锯齿状数组(克隆每一行):copy[j]=锯齿状[j].克隆为双精度[]
实际上我没有,从命令行运行测试产生了类似的结果:克隆锯齿矩阵老派。克隆需要3801ms使用LINQ克隆需要1600ms克隆多维数组。克隆需要484ms在Core i7上使用Benchmark.NET,我在10000次迭代中得到了以下结果:老派:140.38ms,LINQ:151.74 ms,Multi:47.5 ms。您基本上发现了Array.Clone()在CLR内部经过了微优化,它可以使用原始memcpy而无需绑定检查。您永远无法打败它。这也适用于锯齿阵列,但它的惊人速度有助于您发现Clone()的问题,它不是一个深度副本。您通常希望避免索引副本[j]和jaggedMat[j],它们是循环不变的。但是抖动优化器可以自己解决这个问题。我希望您在发布模式下运行测试,并且没有调试器(CTRL+F5或直接在命令行中)…我经常添加进程。GetCurrentProcess().PriorityClass=ProcessPriorityClass.High;
在测试开始时,为了提高程序运行期间的优先级,我会说克隆锯齿状数组应该更慢。请注意,可以半克隆锯齿状数组(克隆每一行):copy[j]=锯齿状[j]。克隆为双[]
实际上我没有,从命令行运行测试产生了类似的结果:克隆锯齿矩阵老派。克隆需要3801ms使用LINQ克隆需要1600ms克隆多维数组。克隆需要484ms在Core i7上使用Benchmark.NET,我在10000次迭代中得到了以下结果:老派:140.38ms,LINQ:151.74 ms,Multi:47.5 ms。您基本上发现了Array.Clone()在CLR内部经过了微优化,它可以使用原始memcpy而无需绑定检查。您永远无法打败它。这也适用于锯齿阵列,但它的惊人速度有助于您发现Clone()的问题,它不是一个深度副本。您通常希望避免索引副本[j]和jaggedMat[j],它们是循环不变的。但是抖动优化器可以自己解决这个问题。我会尝试一下,但要注意的是,您将多维数组称为“jaggedArray”当它不是。是的,那是真的。我的解决方案适用于任何可序列化的对象。如果有人感兴趣,你的方法产生了与l类似的结果