C#中的快速数组复制
本文关键字:数组 复制 | 更新日期: 2023-09-27 17:59:44
我有一个C#类,它包含一个int[]数组(以及其他几个字段,但数组是最主要的)。代码通常会创建此类的副本,分析显示,复制此数组的Array.Copy()调用需要花费大量时间。我能做些什么让它更快?
数组的大小非常小并且是恒定的:有12个元素。所以理想情况下,我想要一个类似C风格的数组:一个位于类内部的内存块(而不是指针)。这在C#中可能吗?(如果需要,我可以使用不安全的代码。)
我已经试过了:
1) 使用UIn64和位移位代替数组。(每个元素的值也很小。)这确实使复制速度很快,但总体上会减慢程序的速度。
2) 为每个数组元素使用单独的字段:int element0、int element1、int element 2等。同样,当我必须访问给定索引处的元素时,这总体上会更慢。
如果您真的关心速度,我会检查System.Buffer.BlockCopy
。
http://msdn.microsoft.com/en-us/library/system.buffer.blockcopy.aspx
简单示例:
int[] a = new int[] {1,2,3,4,5,6,7,8};
int[] b = new int[a.Length];
int size = sizeof(int);
int length = a.Length * size;
System.Buffer.BlockCopy(a, 0, b, 0, length);
在这里进行了精彩的讨论:Array.Copy与Buffer.BlockCopy
这篇文章很旧,但任何与OP处境相似的人都应该看看structs中的固定大小缓冲区。它们正是OP所要求的:一个大小不变的基元类型数组,直接存储在类中。
您可以创建一个结构来表示您的集合,该集合将包含固定大小的缓冲区。数据将直接存储在结构中,结构将直接存储到类中。你可以通过简单的作业进行复制。
它们附带了一些警告:
- 它们只能与基元类型一起使用
- 它们需要在结构中使用"unsafe"关键字
- 在编译时必须知道大小
过去,您必须使用固定关键字和指针来访问它们,但最近针对性能编程对C#进行的更改使这变得不必要。现在,您可以像处理数组一样处理它们。
public unsafe struct MyIntContainer
{
private fixed int myIntegers[12];
public int this[int index]
{
get => this.myIntegers[index];
set => this.myIntegers[index] = value;
}
}
没有内置的绑定检查,因此最好将其包含在这样的属性中,将跳过绑定检查的任何功能封装在方法中。我在手机上,否则我会把它作为我的榜样。
您询问了有关托管阵列的问题。如果您满足于使用fixed
/unsafe
,这可能非常快。
struct
是可赋值的,就像任何基元一样。由于缺少方法调用开销,几乎可以肯定比Buffer.BlockCopy()
或任何其他方法都快:
public unsafe struct MyStruct //the actual struct used, contains all
{
public int a;
public unsafe fixed byte buffer[16];
public ulong b;
//etc.
}
public unsafe struct FixedSizeBufferWrapper //contains _only_ the buffer
{
public unsafe fixed byte buffer[16];
}
unsafe
{
fixed (byte* bufferA = myStructA.buffer, bufferB = myStructB.buffer)
{
*((FixedSizeBufferWrapper*)bufferA) =
*((FixedSizeBufferWrapper*)bufferB);
}
}
我们将每个原始结构的fixed
大小的byte
缓冲区强制转换为包装器指针类型,并取消引用每个指针,这样我们就可以按值将一个指针分配给另一个指针;直接分配fixed
缓冲区是不可能的,因此包装器基本上是零开销的(它只影响指针算术中使用的值)。那个包装只用于铸造。
我们必须进行强制转换,因为(至少在我的C#版本中)我们不能分配除基元类型(通常为byte[]
)之外的任何其他类型作为缓冲区,并且不允许在fixed(...)
内部进行强制转换。
编辑:这似乎被翻译成了对引擎盖下Buffer.Memcpy()
(在我的情况下是Buffer.memcpy4()
,在Unity/Mono中)的调用来进行复制。