一对二对三维阵列,为何速度差?

时间:2009-10-26 11:08:43

标签: .net

当我运行此代码时

Enum l
    NormalFor
    NormalForEach
End Enum

Sub Main()
    run(l.NormalFor)
    run(l.NormalForEach)
    Console.Read()
End Sub

Sub run(ByVal l As l)
    Dim one(999999) As Integer
    Dim two(999, 999) As Integer
    Dim three(99, 99, 99) As Integer
    Dim r As Random
    Dim sw As Stopwatch

    r = New Random(42)
    Select Case l
        Case Module1.l.NormalFor
            sw = Stopwatch.StartNew
            For i = 0 To 999999
                one(i) = r.Next
            Next
            sw.Stop()
        Case Module1.l.NormalForEach
            sw = Stopwatch.StartNew
            For Each i In one
                i = r.Next
            Next
            sw.Stop()
    End Select
    Console.WriteLine("One dimension, Array of " & one.Length.ToString & " items " & sw.ElapsedMilliseconds & "ms (" & l.ToString & ")")

    r = New Random(42)
    Select Case l
        Case Module1.l.NormalFor
            sw = Stopwatch.StartNew
            For i = 0 To 999
                For j = 0 To 999
                    two(i, j) = r.Next
                Next
            Next
            sw.Stop()
        Case Module1.l.NormalForEach
            sw = Stopwatch.StartNew
            For Each i In two
                i = r.Next
            Next
            sw.Stop()
    End Select
    Console.WriteLine("Two dimension, Array of " & two.Length.ToString & " items " & sw.ElapsedMilliseconds & "ms (" & l.ToString & ")")

    r = New Random(42)
    Select Case l
        Case Module1.l.NormalFor
            sw = Stopwatch.StartNew
            For i = 0 To 99
                For j = 0 To 99
                    For k = 0 To 99
                        three(i, j, k) = r.Next
                    Next
                Next
            Next
            sw.Stop()
        Case Module1.l.NormalForEach
            sw = Stopwatch.StartNew
            For Each i In three
                i = r.Next
            Next
            sw.Stop()
    End Select
    Console.WriteLine("Three dimension, Array of " & three.Length.ToString & " items " & sw.ElapsedMilliseconds & "ms (" & l.ToString & ")")
End Sub

我得到了这个结果

  

一维,1000000个项目的数组8ms(NormalFor)
  二维,数组1000000项14ms(NormalFor)
  三维,数组100万件13ms(NormalFor)
  一维,数组1000000项9ms(NormalForEach)
  二维,数组1000000项230ms(NormalForEach)
  三维,数组1000000项241ms(NormalForEach)

任何人都知道为什么使用> = 2维数组会慢一些?

2 个答案:

答案 0 :(得分:3)

CLR支持两种不同的类似数组的类型: vectors arrays 。向量是单维的,并且是从零开始的 - 因此访问元素只是一个例子:

ptr = arrayStart + elementSize * elementIndex

执行非常简单的边界检查:0 <= elementIndex < arraySize

数组(在CLR术语中)可以是多维的并且具有不同的下界 - 因此访问它们需要花费更多的精力。例如,对于二维数组:

ptr = arrayStart + ((elementIndex1 - lowerBound1) * arraySize2
                    + (elementIndex2 - loundBound2)) * elementSize

并使用rank == 2 && lowerBound1 <= elementIndex1 < upperBound1 && lowerBound2 <= elementIndex2 < upperBound2的边界检查。显然这比简单情况要慢得多。

基本上它针对常见的一维零基础情况进行了优化,但是对于真正使事情变得更好的情况支持多维数组。

答案 1 :(得分:0)

我最好的猜测就是内存访问。

内存不是三维数组,它是一维数组。因此,您的3d数组必须转换为1d数据点数组才能放入内存中。这意味着当您访问1d数组中的数据时,它只需要获取数组中第一个数据点的内存位置,并添加偏移量以获取所请求的数据点的位置。

然而,对于3d数组,它必须取第一个点的位置,将您提供的3个偏移相乘以获得1d内存偏移,然后访问内存中的该点。这增加了额外的开销。它不是8毫秒(甚至200毫秒)超过100万件非常非常小。我认为foreach使得差异更加明显,因为它现在必须计算出阵列每个维度的偏移量以及将偏移量转换为1d内存位置。如果.net多维数组实现为数组数组,这意味着foreach必须在为数组的每个维度处理枚举数方面做相当多的工作。

[免责声明:这不是事实,它只是基于记忆知识及其访问方式的理论猜测。]

(不要太担心这个问题,只要对你的数据有意义就使用3d数组。访问时间的差异很小你最好不要让代码可维护和可读而不是试图乱七八糟将3d数据压缩到1d阵列只需几毫秒的性能)