【问题标题】:What way of writing an array is better (CPU Cost)?哪种写数组的方式更好(CPU 成本)?
【发布时间】:2019-02-28 01:47:11
【问题描述】:

我有一个为工作而编写的大型复杂 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 成本?

关于定义数组的不同方法之间的性能差异,我找不到太多。

【问题讨论】:

  • header_arr(6) As String 是一个字符串数组。 Array() 返回的结果是一个Variant,其中包含一个Variants 数组。显然后者的开销更大。
  • Dim header_arr As VariantDim header_arr 完全相同。您不能将 Variant/Array 分配给严格类型的变量,您必须逐行执行。但是,如果函数参数声明为 ByRef ... As Variant,并且相同的函数将能够接受 Variant/Array,则您可以将严格类型的数组传递给函数而不复制数组。使用ByVal ... As Variant 将导致在调用时复制数组。
  • 虽然类型化数组在理论上肯定更快,但我怀疑您是否能够衡量现实世界中的任何差异。不,我相信你不会...
  • "你有两匹马,与它们赛跑!" - 编写代码以提高可读性和易于维护。像这样的微优化应该没有明显的区别 - 没有一揽子答案。既然你不能用Array(...) 定义一个包含 300 万个项目的数组,那又是怎么回事呢?
  • 数组受可用内存 AFAIK 的限制,但是 VBE 中的一行代码不能超过 1023 个字符,并且超过十几个行继续,您开始遇到“太多行继续”编译错误 - 因此内联数组只能包含这么多项目。根据您需要 300 万条记录的目的,Recordset 可能是一个更好的主意。或者这些值可能在工作表上,在这种情况下,您只需一行代码就可以立即将它们放入二维变量数组中。看你需要什么=)

标签: arrays excel vba performance


【解决方案1】:

好的,所以我用一个变体数组和一个字符串数组做了一个测试。让两者都运行几次,似乎带有无类型数组的版本甚至稍微快一些。

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

额外说明:通过引用将数组传递给子例程 1000 次是如此之快,以至于我无法测量它。通过 val 传递它杀死了我的 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 

【讨论】:

  • 感谢您的信息。我需要时间来完成我的项目,但我会回来查看您的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-24
  • 1970-01-01
相关资源
最近更新 更多