programing

C#에서 다차원 배열 "[,]"과 배열 "[][]"의 차이점은 무엇입니까?

stoneblock 2023. 5. 9. 22:02

C#에서 다차원 배열 "[,]"과 배열 "[][]"의 차이점은 무엇입니까?

배열의 차이점은 입니까?double[,] 배열 및 어 이 어double[][]에? C#에?

차이가 있다면요?
각각의 것에 가장 적합한 용도는 무엇입니까?

배열 배열(재그 배열)은 다차원 배열보다 빠르며 더 효과적으로 사용할 수 있습니다.다차원 배열은 구문이 더 좋습니다.

들쭉날쭉한 다차원 배열을 사용하여 간단한 코드를 작성한 다음 컴파일된 어셈블리를 IL 분해기로 검사하면 들쭉날쭉한(또는 단일 차원) 배열에서 저장 및 검색은 단순한 IL 명령인 반면 다차원 배열에 대한 동일한 작업은 항상 느린 메서드 호출임을 알 수 있습니다.

다음 방법을 고려합니다.

static void SetElementAt(int[][] array, int i, int j, int value)
{
    array[i][j] = value;
}

static void SetElementAt(int[,] array, int i, int j, int value)
{
    array[i, j] = value;
}

IL은 다음과 같습니다.

.method private hidebysig static void  SetElementAt(int32[][] 'array',
                                                    int32 i,
                                                    int32 j,
                                                    int32 'value') cil managed
{
  // Code size       7 (0x7)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  ldelem.ref
  IL_0003:  ldarg.2
  IL_0004:  ldarg.3
  IL_0005:  stelem.i4
  IL_0006:  ret
} // end of method Program::SetElementAt

.method private hidebysig static void  SetElementAt(int32[0...,0...] 'array',
                                                    int32 i,
                                                    int32 j,
                                                    int32 'value') cil managed
{
  // Code size       10 (0xa)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  ldarg.2
  IL_0003:  ldarg.3
  IL_0004:  call       instance void int32[0...,0...]::Set(int32,
                                                           int32,
                                                           int32)
  IL_0009:  ret
} // end of method Program::SetElementAt

들쭉날쭉한 배열을 사용하면 행 스왑 및 행 크기 조정과 같은 작업을 쉽게 수행할 수 있습니다.경우에 따라 다차원 어레이를 사용하는 것이 더 안전할 수도 있지만, Microsoft FxCop에서도 프로젝트를 분석할 때 다차원 어레이 대신 들쭉날쭉한 어레이를 사용해야 한다고 말합니다.

다차원 배열은 멋진 선형 메모리 레이아웃을 만드는 반면, 들쭉날쭉한 배열은 몇 가지 추가적인 수준의 간접성을 의미합니다.

하기 가를찾중는치중jagged[3][6] var jagged = new int[10][5]다음과 같은 방식으로 작동합니다.

  • 인덱스 3(어레이)에서 요소를 찾습니다.
  • 배열의 인덱스 6에서 요소(값)를 찾습니다.

이 경우 각 차원에 대해 추가 조회가 있습니다(이는 고가의 메모리 액세스 패턴입니다).

다차원 배열은 메모리에 선형으로 배열되며, 실제 값은 인덱스를 함께 곱하여 찾습니다. " 러나배고할때려을열그때▁however"var mult = new int[10,30],Length해당 다차원 배열의 속성은 총 요소 수(예: 10 * 30 = 300)를 반환합니다.

Rankjagged 배열의 속성은 항상 1이지만 다차원 배열은 임의의 순위를 가질 수 있습니다.GetLength배열의 방법은 각 차원의 길이를 구하는 데 사용될 수 있습니다., 이 다 배 의 경 열 우mult.GetLength(1)30을 반환합니다.

을 인덱싱하는 빠릅니다.를 들어, 이 더 빠릅니다. 예를 들어 이 예에서 다차원 배열이 주어지면mult[1,7]30 * 1 + 7 = 37, 해당 지수 37에서 원소를 구합니다.이는 어레이의 기본 주소인 하나의 메모리 위치만 관련되므로 더 나은 메모리 액세스 패턴입니다.

메모리 블록을 , 배열은 가 없습니다.를 들어, 따서다배차연반할블면메당록, 다들쭉한정배없필니습가요일형사각.jagged[1].Length는 동할필없니다습과 는 없습니다.jagged[2].Length이는 모든 다차원 배열에 해당합니다.

성능

성능 면에서 다차원 어레이는 더 빨라야 합니다.훨씬 빠르지만 CLR 구현이 매우 좋지 않기 때문에 그렇지 않습니다.

 23.084  16.634  15.215  15.489  14.407  13.691  14.695  14.398  14.551  14.252 
 25.782  27.484  25.711  20.844  19.607  20.349  25.861  26.214  19.677  20.171 
  5.050   5.085   6.412   5.225   5.100   5.751   6.650   5.222   6.770   5.305 

첫 번째 행은 들쭉날쭉한 배열의 타이밍이고, 두 번째 행은 다차원 배열을 보여주며, 세 번째 행은 그렇게 되어야 합니다.프로그램은 아래와 같습니다. 참고로 Mono를 실행하여 테스트했습니다. (Windows 타이밍은 CLR 구현에 따라 크게 다릅니다.)

Windows에서 들쭉날쭉한 어레이의 타이밍은 다차원 어레이가 어떻게 보여야 하는지에 대한 필자의 해석과 거의 동일하며 '단일()'을 참조하십시오.안타깝게도 Windows JIT 컴파일러는 정말 어리석고, 이로 인해 안타깝게도 이러한 성능 논의가 어려워지고 불일치가 너무 많습니다.

Windows에서 얻은 타이밍입니다. 첫 번째 행은 들쭉날쭉한 어레이, 두 번째 다차원 및 세 번째 다차원 구현입니다. Mono에 비해 Windows에서 수행하는 속도가 얼마나 느리는지 주목하십시오.

  8.438   2.004   8.439   4.362   4.936   4.533   4.751   4.776   4.635   5.864
  7.414  13.196  11.940  11.832  11.675  11.811  11.812  12.964  11.885  11.751
 11.355  10.788  10.527  10.541  10.745  10.723  10.651  10.930  10.639  10.595

소스 코드:

using System;
using System.Diagnostics;
static class ArrayPref
{
    const string Format = "{0,7:0.000} ";
    static void Main()
    {
        Jagged();
        Multi();
        Single();
    }

    static void Jagged()
    {
        const int dim = 100;
        for(var passes = 0; passes < 10; passes++)
        {
            var timer = new Stopwatch();
            timer.Start();
            var jagged = new int[dim][][];
            for(var i = 0; i < dim; i++)
            {
                jagged[i] = new int[dim][];
                for(var j = 0; j < dim; j++)
                {
                    jagged[i][j] = new int[dim];
                    for(var k = 0; k < dim; k++)
                    {
                        jagged[i][j][k] = i * j * k;
                    }
                }
            }
            timer.Stop();
            Console.Write(Format,
                (double)timer.ElapsedTicks/TimeSpan.TicksPerMillisecond);
        }
        Console.WriteLine();
    }

    static void Multi()
    {
        const int dim = 100;
        for(var passes = 0; passes < 10; passes++)
        {
            var timer = new Stopwatch();
            timer.Start();
            var multi = new int[dim,dim,dim];
            for(var i = 0; i < dim; i++)
            {
                for(var j = 0; j < dim; j++)
                {
                    for(var k = 0; k < dim; k++)
                    {
                        multi[i,j,k] = i * j * k;
                    }
                }
            }
            timer.Stop();
            Console.Write(Format,
                (double)timer.ElapsedTicks/TimeSpan.TicksPerMillisecond);
        }
        Console.WriteLine();
    }

    static void Single()
    {
        const int dim = 100;
        for(var passes = 0; passes < 10; passes++)
        {
            var timer = new Stopwatch();
            timer.Start();
            var single = new int[dim*dim*dim];
            for(var i = 0; i < dim; i++)
            {
                for(var j = 0; j < dim; j++)
                {
                    for(var k = 0; k < dim; k++)
                    {
                        single[i*dim*dim+j*dim+k] = i * j * k;
                    }
                }
            }
            timer.Stop();
            Console.Write(Format,
                (double)timer.ElapsedTicks/TimeSpan.TicksPerMillisecond);
        }
        Console.WriteLine();
    }
}

말해서 .
배열 배열(재그 배열)을 사용하면 각 요소에 동일한 유형의 변수 길이의 다른 배열을 보관할 수 있습니다.

따라서 데이터 구조가 테이블(고정 행/열)처럼 보이는 것이 확실하면 다차원 배열을 사용할 수 있습니다.Jagged 배열은 고정 요소이며 각 요소는 가변 길이의 배열을 수용할 수 있습니다.

예: Psuedo 코드:

int[,] data = new int[2,2];
data[0,0] = 1;
data[0,1] = 2;
data[1,0] = 3;
data[1,1] = 4;

위를 2x2 테이블로 생각해 보십시오.

1 | 2
3 | 4
int[][] jagged = new int[3][]; 
jagged[0] = new int[4] {  1,  2,  3,  4 }; 
jagged[1] = new int[2] { 11, 12 }; 
jagged[2] = new int[3] { 21, 22, 23 }; 

위의 내용을 각 행이 여러 개의 열을 갖는다고 가정합니다.

 1 |  2 |  3 | 4
11 | 12
21 | 22 | 23

갱신하다.NET 6:

의 릴리스와 함께.NET 6 저는 이 주제를 다시 검토할 좋은 시간이라고 결정했습니다.저는 새로운 테스트 코드를 다시 작성했습니다.NET을 사용하여 각 부품이 최소 1초 이상 실행되도록 했습니다.이 벤치마크는 AMD Ryzen 5600x에서 수행되었습니다.

결과?복잡해요.단일 어레이는 소규모 및 대규모 어레이(< ~25x25x25 & > ~200x200x200)에서 가장 성능이 우수하며, 그 사이에서 가장 빠른 Jagged 어레이가 있습니다.안타깝게도 제가 테스트해 본 결과 다차원적인 선택이 가장 느린 것으로 나타났습니다.가장 빠른 옵션보다 최대 두 배 더 느린 속도로 수행할 수 있습니다.하지만, 50^3 큐브에서 Jagged 어레이를 초기화하는 데 시간이 훨씬 오래 걸릴 수 있기 때문에 어레이가 필요한 용도에 따라 다릅니다. 초기화 시간은 단일 차원보다 약 3배 더 길었습니다.다차원은 1차원보다 조금 느렸습니다.

결론은?빠른 코드가 필요한 경우 실행할 시스템에서 직접 벤치마킹하십시오.CPU 아키텍처는 각 방법의 상대적 성능을 완전히 변경할 수 있습니다.

숫자!

Method name         Ticks/Iteration     Scaled to the best
Array size 1x1x1 (10,000,000 iterations):
Jagged:             0.15                4.28
Single:             0.035               1
Multi-dimensional:  0.77                22

Array size 10x10x10 (25,000 iterations):
Jagged:             15                  1.67
Single:             9                   1
Multi-dimensional:  56                  6.2

Array size 25x25x25 (25,000 iterations):
Jagged:             157                 1.3
Single:             120                 1
Multi-dimensional:  667                 5.56

Array size 50x50x50 (10,000 iterations):
Jagged:             1,140               1
Single:             2,440               2.14
Multi-dimensional:  5,210               4.57

Array size 100x100x100 (10,000 iterations):
Jagged:             9,800               1
Single:             19,800              2
Multi-dimensional:  41,700              4.25

Array size 200x200x200 (1,000 iterations):
Jagged:             161,622             1
Single:             175,507             1.086
Multi-dimensional:  351,275             2.17

Array size 500x500x500 (100 iterations):
Jagged:             4,057.413           1.5
Single:             2,709,301           1
Multi-dimensional:  5,359,393           1.98

날 믿지 마?직접 실행하여 확인합니다.

참고: 일정한 크기는 들쭉날쭉한 어레이에 우위를 제공하는 것처럼 보이지만 벤치마크의 순서를 변경하기에는 충분하지 않습니다.어떤 경우에는 들쭉날쭉한 어레이에 대해 사용자 입력 크기를 사용할 때 성능이 최대 7% 감소하고, 단일 어레이에 대해서는 차이가 없으며, 다차원 어레이에 대해서는 매우 작은 차이(~1% 이하)를 측정했습니다.들쭉날쭉한 배열이 선두를 달리는 가운데가 가장 눈에 띕니다.

    using System.Diagnostics;

const string Format = "{0,7:0.000} ";
const int TotalPasses = 25000;
const int Size = 50;
Stopwatch timer = new();

var functionList = new List<Action> { Jagged, Single, SingleStandard, Multi };

Console.WriteLine("{0,5}{1,20}{2,20}{3,20}{4,20}", "Run", "Ticks", "ms", "Ticks/Instance", "ms/Instance");

foreach (var item in functionList)
{
    var warmup = Test(item);
    var run = Test(item);

    Console.WriteLine($"{item.Method.Name}:");
    PrintResult("warmup", warmup);
    PrintResult("run", run);
    Console.WriteLine();
}

static void PrintResult(string name, long ticks)
{
    Console.WriteLine("{0,10}{1,20}{2,20}{3,20}{4,20}", name, ticks, string.Format(Format, (decimal)ticks / TimeSpan.TicksPerMillisecond), (decimal)ticks / TotalPasses, (decimal)ticks / TotalPasses / TimeSpan.TicksPerMillisecond);
}

long Test(Action func)
{
    timer.Restart();
    func();
    timer.Stop();
    return timer.ElapsedTicks;
}

static void Jagged()
{
    for (var passes = 0; passes < TotalPasses; passes++)
    {
        var jagged = new int[Size][][];
        for (var i = 0; i < Size; i++)
        {
            jagged[i] = new int[Size][];
            for (var j = 0; j < Size; j++)
            {
                jagged[i][j] = new int[Size];
                for (var k = 0; k < Size; k++)
                {
                    jagged[i][j][k] = i * j * k;
                }
            }
        }
    }
}

static void Multi()
{
    for (var passes = 0; passes < TotalPasses; passes++)
    {
        var multi = new int[Size, Size, Size];
        for (var i = 0; i < Size; i++)
        {
            for (var j = 0; j < Size; j++)
            {
                for (var k = 0; k < Size; k++)
                {
                    multi[i, j, k] = i * j * k;
                }
            }
        }
    }
}

static void Single()
{
    for (var passes = 0; passes < TotalPasses; passes++)
    {
        var single = new int[Size * Size * Size];
        for (var i = 0; i < Size; i++)
        {
            int iOffset = i * Size * Size;
            for (var j = 0; j < Size; j++)
            {
                var jOffset = iOffset + j * Size;
                for (var k = 0; k < Size; k++)
                {
                    single[jOffset + k] = i * j * k;
                }
            }
        }
    }
}

static void SingleStandard()
{
    for (var passes = 0; passes < TotalPasses; passes++)
    {
        var single = new int[Size * Size * Size];
        for (var i = 0; i < Size; i++)
        {
            for (var j = 0; j < Size; j++)
            {
                for (var k = 0; k < Size; k++)
                {
                    single[i * Size * Size + j * Size + k] = i * j * k;
                }
            }
        }
    }
}

배운 교훈:차이가 있기 때문에 항상 벤치마크에 CPU를 포함해야 합니다.이번엔 그랬나요?저는 모르겠지만 아마 그랬을 거라고 생각해요.


원답:

에 있기 때문에 이에 대한 업데이트를 위해서입니다.NET Core 다차원 어레이는 들쭉날쭉한 어레이보다 빠릅니다.저는 John Leidegren의 테스트를 실행했고 이것은 에 대한 결과입니다.NET Core 2.0 미리 보기 2.백그라운드 앱에서 발생할 수 있는 영향을 덜 보이게 하기 위해 치수를 늘렸습니다.

Debug (code optimalization disabled)
Running jagged 
187.232 200.585 219.927 227.765 225.334 222.745 224.036 222.396 219.912 222.737 

Running multi-dimensional  
130.732 151.398 131.763 129.740 129.572 159.948 145.464 131.930 133.117 129.342 

Running single-dimensional  
 91.153 145.657 111.974  96.436 100.015  97.640  94.581 139.658 108.326  92.931 


Release (code optimalization enabled)
Running jagged 
108.503 95.409 128.187 121.877 119.295 118.201 102.321 116.393 125.499 116.459 

Running multi-dimensional 
 62.292  60.627  60.611  60.883  61.167  60.923  62.083  60.932  61.444  62.974 

Running single-dimensional 
 34.974  33.901  34.088  34.659  34.064  34.735  34.919  34.694  35.006  34.796 

조립품을 조사해 봤는데 이게 제가 발견한 것은

jagged[i][j][k] = i * j * k; 34의실침이함을 실행하기 위해 34개의 했습니다.

multi[i, j, k] = i * j * k;하기 위해서는 이 필요했습니다.

single[i * dim * dim + j * dim + k] = i * j * k;하기 위해서는 이 필요했습니다.

왜 아직도 1차원 어레이가 다차원 어레이보다 빠른지는 알 수 없었지만 CPU에서 수행된 최적화와 관련이 있을 것으로 추측됩니다.

서문:이 설명은 들쭉날쭉한 배열과 다차원 배열 간의 성능 차이에 대해 Okutane이 제공한 답변을 설명하기 위한 것입니다.

메서드 호출로 인해 한 유형이 다른 유형보다 느리다는 주장은 올바르지 않습니다.하나는 더 복잡한 경계 검사 알고리즘 때문에 다른 하나보다 느립니다.IL이 아닌 컴파일된 어셈블리를 보면 쉽게 확인할 수 있습니다.예를 들어, 4.5 설치에서 인덱스가 eax와 edx에 저장된 상태에서 ecx가 가리키는 2차원 배열에 저장된 요소(edx의 포인터를 통해)에 액세스하는 것은 다음과 같습니다.

sub eax,[ecx+10]
cmp eax,[ecx+08]
jae oops //jump to throw out of bounds exception
sub edx,[ecx+14]
cmp edx,[ecx+0C]
jae oops //jump to throw out of bounds exception
imul eax,[ecx+0C]
add eax,edx
lea edx,[ecx+eax*4+18]

여기서 메서드 호출의 오버헤드가 없음을 알 수 있습니다.경계 검사는 0이 아닌 인덱스의 가능성 덕분에 매우 복잡하며, 이는 들쭉날쭉한 배열에서는 제공되지 않는 기능입니다.만약 우리가 그것을 제거한다면.sub,cmp,그리고.jmp s 으로 해결됩니다.(x*y_max+y)*sizeof(ptr)+sizeof(array_header)이 계산은 요소에 대한 임의 액세스를 위해 다른 것과 마찬가지로 빠릅니다(1 곱하기 2는 시프트로 대체될 수 있습니다. 이는 2비트의 거듭제곱으로 크기를 결정하는 전체 이유이기 때문입니다).

또 다른 복잡성은 현대 컴파일러가 단일 차원 배열을 반복하는 동안 요소 액세스를 위해 중첩된 경계 검사를 최적화하는 경우가 많다는 것입니다.그 결과 기본적으로 인덱스 포인터를 배열의 인접 메모리로 이동시키는 코드가 생성됩니다.다차원 배열에 대한 단순 반복은 일반적으로 중첩된 논리의 추가 계층을 포함하므로 컴파일러가 작업을 최적화할 가능성이 낮습니다.따라서 단일 요소에 액세스할 때의 경계 검사 오버헤드가 어레이 치수 및 크기와 관련하여 일정한 런타임으로 상각되더라도, 그 차이를 측정하기 위한 단순한 테스트 사례는 실행하는 데 몇 배나 더 오래 걸릴 수 있습니다.

다차원 배열은 (n-1)차원 행렬입니다.

그렇게int[,] square = new int[2,2] 행렬 제곱행 2x2니다입니다.int[,,] cube = new int [3,3,3]는 입방체-제곱 행렬 3x3입니다.비례성은 필요하지 않습니다.

jagged 배열은 배열의 배열일 뿐이며, 각 셀에 배열이 포함된 배열입니다.

따라서 MDA는 비례하지만 JD는 그렇지 않을 수 있습니다!각 셀에는 임의 길이의 배열이 포함될 수 있습니다!

위의 답변에서 언급되었을 수 있지만 명시적이지는 않습니다. Jagged Array를 사용하면 사용할 수 있습니다.array[row]전체 데이터 행을 참조하지만 다중 D 배열에는 허용되지 않습니다.

다른 답변 외에도 다차원 배열이 힙에서 하나의 크고 무거운 개체로 할당됩니다.이는 다음과 같은 몇 가지 의미가 있습니다.

  1. 일부 다차원 어레이는 동일한 들쭉날쭉한 어레이가 없는 LOH(Large Object Hip)에 할당됩니다.
  2. GC는 다차원 배열을 할당하기 위해 연속적으로 사용 가능한 단일 메모리 블록을 찾아야 하는 반면, 들쭉날쭉한 배열은 힙 조각화로 인한 공백을 채울 수 있습니다.이것은 보통 에서 이슈가 되지 않습니다.압축으로 인한 NET, 그러나 LOH는 기본적으로 압축되지 않습니다(요청해야 하며, 원할 때마다 요청해야 합니다).
  3. 들쭉날쭉한 어레이만 사용하는 경우 문제가 발생하기 전에 다차원 어레이를 조사해야 합니다.

저는 앞으로 여기서 공연 결과를 발표할 거라고 생각했습니다.앞으로 모두가 사용하는 플랫폼이 될 것으로 보이는 NET 5.

이것은 John Leidegren이 2009년에 사용한 것과 동일한 테스트입니다.

내 결과(.NET 5.0.1):

  Debug:
  (Jagged)
  5.616   4.719   4.778   5.524   4.559   4.508   5.913   6.107   5.839   5.270
  
  (Multi)
  6.336   7.477   6.124   5.817   6.516   7.098   5.272   6.091  25.034   6.023
  
  (Single)
  4.688   3.494   4.425   6.176   4.472   4.347   4.976   4.754   3.591   4.403


  Release(code optimizations on):
  (Jagged)
  2.614   2.108   3.541   3.065   2.172   2.936   1.681   1.724   2.622   1.708

  (Multi)
  3.371   4.690   4.502   4.153   3.651   3.637   3.580   3.854   3.841   3.802

  (Single)
  1.934   2.102   2.246   2.061   1.941   1.900   2.172   2.103   1.911   1.911

6코어 3.7에서 실행GHz AMD 라이젠 1600 기계.

성능비는 여전히 거의 동일한 것으로 보입니다.정말로 열심히 최적화하는 것이 아니라면, 구문이 조금 더 사용하기 쉽기 때문에 다차원 배열을 사용하십시오.

Jagged 배열은 각 행에 고유한 배열이 포함된 배열 또는 배열의 배열입니다.

이러한 배열의 길이는 다른 행의 길이와 다를 수 있습니다.

어레이 선언 및 할당

일반 다차원 배열과 비교하여 들쭉날쭉한 배열의 선언에서 유일한 차이점은 괄호 한 쌍만 가지고 있지 않다는 것입니다.들쭉날쭉한 배열을 사용하면 차원당 한 쌍의 브래킷이 있습니다.다음과 같은 방식으로 할당합니다.

int[][] exampleJaggedArray;
jaggedArray = new int[2][];
jaggedArray[0] = new int[5];
jaggedArray[1] = new int[3];

배열 초기화

int[][] exampleJaggedArray = {
new int[] {5, 7, 2},
new int[] {10, 20, 40},
new int[] {3, 25}
};

메모리 할당

Jagged 배열은 참조의 집합입니다.jagged 배열은 배열을 직접 포함하지 않고 배열을 가리키는 요소를 포함합니다.크기를 알 수 없으므로 CLR은 내부 어레이에 대한 참조만 유지합니다.Jagged 배열의 하나의 배열 요소에 메모리를 할당한 후 참조가 동적 메모리에서 새로 생성된 블록을 가리키기 시작합니다.

변수 예제 JaggedArray는 프로그램의 실행 스택에 저장되고 동적 메모리의 블록을 가리킵니다. 여기에는 메모리의 다른 세 블록에 대한 세 개의 참조 시퀀스가 포함되어 있습니다. 각 블록에는 JaggedArray의 요소인 정수 배열이 포함되어 있습니다.

변환을 수행하는 데 사용할 Assembly, 클래스, 메서드 및 저장 프로시저의 데이터베이스를 구축하기 위해 idasm에서 생성된 .il 파일을 구문 분석하고 있습니다.저는 다음과 같은 것을 발견했고, 그것은 제 구문 분석을 중단시켰습니다.

.method private hidebysig instance uint32[0...,0...] 
        GenerateWorkingKey(uint8[] key,
                           bool forEncryption) cil managed

전문가라는 책.NET 2.0 IL Assembler, Serge Lidin, Apress, 2006, 8장, 원시 유형 및 서명, 페이지 149-150이 설명합니다.

<type>[]를 라고 합니다.<type>,

<type>[<bounds> [<bounds>**] ]를 의배라합니다고의 이라고 합니다.<type>

**될 수 .[ ]옵션을 의미합니다.

설정:허락하다<type> = int32.

1)int32[...,...]되지 않은 입니다.

2)int32[2...5]하한 2 및 크기 4의 1차원 배열입니다.

3)int32[0...,0...]하한 0과 정의되지 않은 크기의 2차원 배열입니다.

톰.

John Leidegren의 테스트를 기반으로 한 테스트를 사용하여 결과를 벤치마킹했습니다.NET 4.7.2는 제 목적과 공유할 수 있을 것으로 생각되는 관련 버전입니다.저는 원래 닷넷 코어 깃허브 저장소에서 이 의견으로 시작했습니다.

적어도 내 설정에서는 4개의 물리적 8개의 논리적 프로세서가 있는 1개의 프로세서 Xeon에서 어레이 크기가 변경됨에 따라 성능이 크게 달라지는 것으로 보입니다.

w = 배열을 초기화하고 i * j를 입력합니다. wr = dow를 입력한 다음 int x를 [i,j]로 설정합니다.

배열 크기가 커질수록 다차원이 성능을 능가하는 것으로 나타납니다.

크기 rw 방법 의미하다 오류 표준 개발 Gen 0/1k Op Gen 1/1k Op 2세대/1k 작동 할당된 메모리/Op
1800*500 w 들쭉날쭉한 2.445ms 0.0959ms 0.1405ms 578.1250 281.2500 85.9375 3.46MB
1800*500 w 멀티 3.079ms 0.2419ms 0.3621ms 269.5313 269.5313 269.5313 3.43MB
2000*4000 w 들쭉날쭉한 50.29ms 3.262ms 4.882ms 5937.5000 3375.0000 937.5000 30.62MB
2000*4000 w 멀티 26.34ms 1.797ms 2.690ms 218.7500 218.7500 218.7500 30.52MB
2000*4000 짜다 들쭉날쭉한 55.30ms 3.066ms 4.589ms 5937.5000 3375.0000 937.5000 30.62MB
2000*4000 짜다 멀티 32.23ms 2.798ms 4.196ms 285.7143 285.7143 285.7143 30.52MB
1000*2000 짜다 들쭉날쭉한 11.18ms 0.5397ms 0.8078ms 1437.5000 578.1250 234.3750 7.69MB
1000*2000 짜다 멀티 6.622ms 0.3238ms 0.4847ms 210.9375 210.9375 210.9375 7.63MB

업데이트: int[,] 대신 더블[,]을 사용한 마지막 두 테스트.오차를 고려할 때 차이가 상당한 것으로 보입니다.int의 경우 들쭉날쭉한 평균 대 md의 비율은 1.53배와 1.86배 사이이고, 두 배는 1.88배와 2.42배입니다.

크기 rw 방법 의미하다 오류 표준 개발 Gen 0/1k Op Gen 1/1k Op 2세대/1k 작동 할당된 메모리/Op
1000*2000 짜다 들쭉날쭉한 26.83ms 1.196ms 1.790ms 3062.5000 1531.2500 531.2500 15.31MB
1000*2000 짜다 멀티 12.61ms 1.018ms 1.524ms 156.2500 156.2500 156.2500 15.26MB

언급URL : https://stackoverflow.com/questions/597720/differences-between-a-multidimensional-array-and-an-array-of-arrays