Qualquer maneira mais rápida de copiar matrizes em c #?

Eu tenho três matrizes que precisam ser combinadas em um array de três dimensões. O código a seguir mostra um desempenho lento no Performance Explorer. Existe uma solução mais rápida?

for (int i = 0; i < sortedIndex.Length; i++) { if (i < num_in_left) { // add instance to the left child leftnode[i, 0] = sortedIndex[i]; leftnode[i, 1] = sortedInstances[i]; leftnode[i, 2] = sortedLabels[i]; } else { // add instance to the right child rightnode[i-num_in_left, 0] = sortedIndex[i]; rightnode[i-num_in_left, 1] = sortedInstances[i]; rightnode[i-num_in_left, 2] = sortedLabels[i]; } } 

Atualizar:

Eu estou realmente tentando fazer o seguinte:

 //given three 1d arrays double[] sortedIndex, sortedInstances, sortedLabels; // copy them over to a 3d array (forget about the rightnode for now) double[] leftnode = new double[sortedIndex.Length, 3]; // some magic happens here so that leftnode = {sortedIndex, sortedInstances, sortedLabels}; 

    Use Buffer.BlockCopy . Todo o seu propósito é executar rapidamente (veja Buffer ):

    Essa class fornece melhor desempenho para manipular tipos primitivos que methods semelhantes na class System.Array.

    Evidentemente, eu não fiz nenhum benchmark, mas essa é a documentação. Também funciona em matrizes multidimensionais; apenas certifique-se de estar sempre especificando quantos bytes copiar, não quantos elementos e também que você está trabalhando em um array primitivo.

    Além disso, eu não testei isso, mas você pode conseguir extrair um pouco mais de desempenho do sistema se ligar um delegado a System.Buffer.memcpyimpl e chamar isso diretamente. A assinatura é:

     internal static unsafe void memcpyimpl(byte* src, byte* dest, int len) 

    Ele requer pointers, mas acredito que ele é otimizado para a maior velocidade possível, e, portanto, não acho que haja uma maneira de chegar mais rápido do que isso, mesmo se você tivesse uma assembly em mãos.


    Atualização :

    Devido a pedidos (e para satisfazer minha curiosidade), eu testei isso:

     using System; using System.Diagnostics; using System.Reflection; unsafe delegate void MemCpyImpl(byte* src, byte* dest, int len); static class Temp { //There really should be a generic CreateDelegate() method... -___- static MemCpyImpl memcpyimpl = (MemCpyImpl)Delegate.CreateDelegate( typeof(MemCpyImpl), typeof(Buffer).GetMethod("memcpyimpl", BindingFlags.Static | BindingFlags.NonPublic)); const int COUNT = 32, SIZE = 32 < < 20; //Use different buffers to help avoid CPU cache effects static byte[] aSource = new byte[SIZE], aTarget = new byte[SIZE], bSource = new byte[SIZE], bTarget = new byte[SIZE], cSource = new byte[SIZE], cTarget = new byte[SIZE]; static unsafe void TestUnsafe() { Stopwatch sw = Stopwatch.StartNew(); fixed (byte* pSrc = aSource) fixed (byte* pDest = aTarget) for (int i = 0; i < COUNT; i++) memcpyimpl(pSrc, pDest, SIZE); sw.Stop(); Console.WriteLine("Buffer.memcpyimpl: {0:N0} ticks", sw.ElapsedTicks); } static void TestBlockCopy() { Stopwatch sw = Stopwatch.StartNew(); sw.Start(); for (int i = 0; i < COUNT; i++) Buffer.BlockCopy(bSource, 0, bTarget, 0, SIZE); sw.Stop(); Console.WriteLine("Buffer.BlockCopy: {0:N0} ticks", sw.ElapsedTicks); } static void TestArrayCopy() { Stopwatch sw = Stopwatch.StartNew(); sw.Start(); for (int i = 0; i < COUNT; i++) Array.Copy(cSource, 0, cTarget, 0, SIZE); sw.Stop(); Console.WriteLine("Array.Copy: {0:N0} ticks", sw.ElapsedTicks); } static void Main(string[] args) { for (int i = 0; i < 10; i++) { TestArrayCopy(); TestBlockCopy(); TestUnsafe(); Console.WriteLine(); } } } 

    Os resultados:

     Buffer.BlockCopy: 469,151 ticks Array.Copy: 469,972 ticks Buffer.memcpyimpl: 496,541 ticks Buffer.BlockCopy: 421,011 ticks Array.Copy: 430,694 ticks Buffer.memcpyimpl: 410,933 ticks Buffer.BlockCopy: 425,112 ticks Array.Copy: 420,839 ticks Buffer.memcpyimpl: 411,520 ticks Buffer.BlockCopy: 424,329 ticks Array.Copy: 420,288 ticks Buffer.memcpyimpl: 405,598 ticks Buffer.BlockCopy: 422,410 ticks Array.Copy: 427,826 ticks Buffer.memcpyimpl: 414,394 ticks 

    Agora mude a ordem:

     Array.Copy: 419,750 ticks Buffer.memcpyimpl: 408,919 ticks Buffer.BlockCopy: 419,774 ticks Array.Copy: 430,529 ticks Buffer.memcpyimpl: 412,148 ticks Buffer.BlockCopy: 424,900 ticks Array.Copy: 424,706 ticks Buffer.memcpyimpl: 427,861 ticks Buffer.BlockCopy: 421,929 ticks Array.Copy: 420,556 ticks Buffer.memcpyimpl: 421,541 ticks Buffer.BlockCopy: 436,430 ticks Array.Copy: 435,297 ticks Buffer.memcpyimpl: 432,505 ticks Buffer.BlockCopy: 441,493 ticks 

    Agora mude a ordem novamente:

     Buffer.memcpyimpl: 430,874 ticks Buffer.BlockCopy: 429,730 ticks Array.Copy: 432,746 ticks Buffer.memcpyimpl: 415,943 ticks Buffer.BlockCopy: 423,809 ticks Array.Copy: 428,703 ticks Buffer.memcpyimpl: 421,270 ticks Buffer.BlockCopy: 428,262 ticks Array.Copy: 434,940 ticks Buffer.memcpyimpl: 423,506 ticks Buffer.BlockCopy: 427,220 ticks Array.Copy: 431,606 ticks Buffer.memcpyimpl: 422,900 ticks Buffer.BlockCopy: 439,280 ticks Array.Copy: 432,649 ticks 

    ou, em outras palavras: eles são muito competitivos; Como regra geral, o memcpyimpl é o mais rápido, mas não vale necessariamente a pena se preocupar.

    Você pode usar o Array.Copy .

    EDITAR

    Array.Copy funciona para matrizes multidimensionais: consulte este tópico .

    Para matrizes de tipo primitivo (como double ) você pode copiar rapidamente, mesmo para array multidimensional com pointers.

    No código abaixo eu inicializo um array 2D A[10,10] com os valores de 1 a 100. Então eu copio esses valores em um array 1D B[100]

     unsafe class Program { static void Main(string[] args) { double[,] A = new double[10, 10]; for(int i = 0; i < 10; i++) { for(int j = 0; j < 10; j++) { A[i, j] = 10 * i + j + 1; } } // A has { { 1 ,2 .. 10}, { 11, 12 .. 20}, .. { .. 99, 100} } double[] B = new double[10 * 10]; if (A.Length == B.Length) { fixed (double* pA = A, pB = B) { for(int i = 0; i < B.Length; i++) { pB[i] = pA[i]; } } // B has {1, 2, 3, 4 .. 100} } } } 

    Quão rápido é isso. Meu teste mostrou que ele é muitas vezes mais rápido do que a cópia C # nativa e o Buffer.BlockCopy() . Você tenta o seu caso e nos avisa.

    Editar 1 Eu comparei a cópia com quatro methods. 1) Dois loops nesteds, 2) Um loop serial, 3) Ponteiros, 4) BlockCopy. Eu medi o número de cópias por tick para várias matrizes de tamanho.

     N = 10x 10 (cpy/tck) Nested = 50, Serial = 33, Pointer = 100, Buffer = 16 N = 20x 20 (cpy/tck) Nested = 133, Serial = 40, Pointer = 400, Buffer = 400 N = 50x 50 (cpy/tck) Nested = 104, Serial = 40, Pointer = 2500, Buffer = 2500 N = 100x 100 (cpy/tck) Nested = 61, Serial = 41, Pointer = 10000, Buffer = 3333 N = 200x 200 (cpy/tck) Nested = 84, Serial = 41, Pointer = 40000, Buffer = 2666 N = 500x 500 (cpy/tck) Nested = 69, Serial = 41, Pointer = 125000, Buffer = 2840 N = 1000x1000 (cpy/tck) Nested = 33, Serial = 45, Pointer = 142857, Buffer = 1890 N = 2000x2000 (cpy/tck) Nested = 30, Serial = 43, Pointer = 266666, Buffer = 1826 N = 5000x5000 (cpy/tck) Nested = 21, Serial = 42, Pointer = 735294, Buffer = 1712 

    Está claro aqui quem é o vencedor. Cópia de ponteiro é ordens de magnitudes melhor que qualquer outro método.

    Edit 2 Aparentemente eu estava injustamente aproveitando uma otimização de compilador / JIT porque quando eu movia os loops para trás dos delegates para equalizar o campo de jogo, os números mudavam drasticamente.

     N = 10x 10 (cpy/tck) Nested = 0, Serial = 0, Pointer = 0, Buffer = 0 N = 20x 20 (cpy/tck) Nested = 80, Serial = 14, Pointer = 100, Buffer = 133 N = 50x 50 (cpy/tck) Nested =147, Serial = 15, Pointer = 277, Buffer = 2500 N = 100x 100 (cpy/tck) Nested = 98, Serial = 15, Pointer = 285, Buffer = 3333 N = 200x 200 (cpy/tck) Nested =106, Serial = 15, Pointer = 272, Buffer = 3076 N = 500x 500 (cpy/tck) Nested =106, Serial = 15, Pointer = 276, Buffer = 3125 N = 1000x1000 (cpy/tck) Nested =101, Serial = 11, Pointer = 199, Buffer = 1396 N = 2000x2000 (cpy/tck) Nested =105, Serial = 9, Pointer = 186, Buffer = 1804 N = 5000x5000 (cpy/tck) Nested =102, Serial = 8, Pointer = 170, Buffer = 1673 

    A cópia em buffer está no topo aqui (graças a @ Mehrdad) com cópia em segundo ponteiro. A questão agora é por que a cópia do ponteiro não é tão rápida quanto os methods de buffer?