如何编写数组更加高效(CPU成本)?

3

我有一个为工作编写的大型复杂的VBA脚本。我正在整理它,并注意到我可以以比之前更加动态的方式来定义我的数组。

最初,我是像这样定义我的字符串数组的:

Dim header_arr(6) As String
Dim header_arr_2(4) As String

header_arr(0) = "esn"
header_arr(1) = "vin"
header_arr(2) = "last gps update time"
header_arr(3) = "status"
header_arr(4) = "account name"
header_arr(5) = "vehicle #"

header_arr_2(0) = "esn"
header_arr_2(1) = "vin"
header_arr_2(2) = "last gps update time"
header_arr_2(3) = "status"
header_arr_2(4) = "vehicle #"

然后我在尝试如何分配一个数组时,设法将其简化为以下内容:

Dim header_arr

header_arr = Array("esn", "vin", "last gps update time", "status", "account name", "vehicle #")
' Function call with this first Array

header_arr = Array("esn", "vin", "last gps update time", "status", "vehicle #")
' Function call with this second Array

我的问题是:

我知道对于这个简单的脚本部分,CPU成本并不相关,但对于更大的数组,如果有任何差异,写入数组的最低CPU成本方法是什么?

我没有找到有关定义数组的不同方法之间性能差异的太多信息。


1
header_arr(6) As String 是一个字符串数组。Array() 返回的结果是一个 Variant,包含了一个 Variant 数组。显然后者有更多的开销。 - GSerg
1
Dim header_arr As VariantDim header_arr 是完全相同的。你不能将一个 Variant/Array 直接赋值给一个严格类型的变量,必须逐行进行赋值。但是,如果函数参数声明为 ByRef ... As Variant,则可以将严格类型的数组传递给函数而不复制数组,并且该函数也能够接受 Variant/Array。使用 ByVal ... As Variant 将导致在调用时复制数组。 - GSerg
3
"你有两匹马,比赛它们!" - 写出易读且易于维护的代码。微小的优化不会带来明显的差异 - 没有一种通用的答案。由于你不能使用 Array(...) 在行内定义一个含有 3 百万项的数组,那么这是怎么回事呢?" - Mathieu Guindon
2
数组在可用内存方面受到限制,据我所知,但是VBE中的一行代码不能超过1023个字符,在超过十几个行连续后,您会开始遇到“太多行连续”编译错误 - 因此,内联数组只能包含这么多项。根据您需要3百万条记录的情况,Recordset可能是一个更好的选择。或者这些值可能在工作表上,在这种情况下,您可以使用一行代码将它们快速转换为2D变体数组。取决于您的需求=) - Mathieu Guindon
1
@GSerg Dim header_arr() As VariantDim header_arr() 都可以让你得到一个变量数组,但是第一个选项更清晰地表明了你的意图。这对于未来阅读你代码的任何人(包括你自己)都是有益的。 - FreeMan
显示剩余7条评论
1个回答

1

好的,我用一个变体数组和一个字符串数组做了一个测试。让它们都运行几次,似乎使用未经类型定义的数组版本甚至更快。

但更重要的教训是:字符串处理本身(这是一个相当简单的处理,连接字符串和数字)消耗了 75% 的运行时间 - 因此,数组本身的数据类型并不真正重要。

另外一点说明:将数组按引用传递给子程序1000次是非常快的,我无法测量它。通过值传递使我的 Excel 崩溃了。但是,通过值传递数组几乎肯定不是你想做的事情。

我使用了以下代码:

Option Explicit

Private mlngStart As Long
Private Declare Function GetTickCount Lib "kernel32" () As Long

Const size = 3000000

Dim startTime As Long
Public Sub StartTimer()
    startTime = GetTickCount
End Sub

Public Function EndTimer() As Long
    EndTimer = (GetTickCount - startTime)
End Function


Sub b1()

    StartTimer
    Dim i As Long
    Dim s(size)
    For i = 1 To size
        s(i) = "ABC"
    Next i
    Debug.Print "untyped, size = " & size, EndTimer
End Sub

Sub b2()
    StartTimer
    Dim i As Long
    Dim s(size) As String
    For i = 1 To size
        s(i) = "ABC"
    Next i
    Debug.Print "as string, size = " & size, EndTimer
End Sub

结果是:
untyped, size = 3000000      312 
untyped, size = 3000000      313 
untyped, size = 3000000      313 
untyped, size = 3000000      297 
untyped, size = 3000000      313 
as string, size = 3000000    328 
as string, size = 3000000    313 
as string, size = 3000000    328 
as string, size = 3000000    344 
as string, size = 3000000    313 

我将赋值改为s(i) = "ABC" & i,得到了以下结果:

untyped, size = 3000000      922 
untyped, size = 3000000      953 
untyped, size = 3000000      938 
untyped, size = 3000000      1015 
untyped, size = 3000000      953 
as string, size = 3000000    1140 
as string, size = 3000000    1156 
as string, size = 3000000    1157 
as string, size = 3000000    1125 
as string, size = 3000000    1125 

谢谢提供信息。我需要时间来完成我的项目,但我会回来查看你的答案。 - Mike - SMT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接