当我运行此代码时
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维数组会慢一些?
答案 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阵列只需几毫秒的性能)