与访问用户定义类型的字段相比,VBA类模块属性是否较慢?

rpe*_*z86 5 excel vba excel-vba

我一直在尝试使用类模块开发一个宏,但是与UDT相比,get/let似乎需要很长时间.我真的很感兴趣为什么会这样,有人可以解释一下吗?我只发现了讨论功能/子执行的讨论,这似乎同样快.

目前的问题是设置一个属性,该类需要大约3000毫秒(200万次)和120毫秒使用UDT进行相同操作.

我正在尝试决定是否应该建议宏开发人员在需要获取或设置大量属性时避免使用类模块.只使用这个作为我应该的数据,但也许你有不同的见解.

我想明白为什么这么慢.也许我只是做错了什么.

示例代码:

Public Type Participant
    Name As String
    Gender As Integer
End Type

Public Declare Function GetTickCount Lib "kernel32.dll" () As Long

Sub TimeUDT()
   Dim i As Long
   Dim startMs As Long
   startMs = GetTickCount
   Dim participants(1 To 1000000) As Participant
   For i = 1 To 1000000
      participants(i).Name = "TestName"
      participants(i).Gender = 1
   Next
   Debug.Print GetTickCount - startMs
End Sub

Sub TimeCls()
   Dim i As Long
   Dim startMs As Long
   Dim participants(1 To 1000000) As New clsParticipant
   startMs = GetTickCount
   For i = 1 To 1000000
      participants(i).Name = "TestName"
      participants(i).Gender = 1
   Next
   Debug.Print GetTickCount - startMs
End Sub
Run Code Online (Sandbox Code Playgroud)

和类模块(名为clsParticipant):

Private iGender As Integer
Private sName As String

Public Property Let Gender(value As Integer)
   iGender = value
End Property
Public Property Get Gender() As Integer
   Gender = iGender
End Property

Public Property Get Name() As String
   Name = sName
End Property
Public Property Let Name(value As String)
   sName = value
End Property
Run Code Online (Sandbox Code Playgroud)

A. *_*ebb 10

首先,我强烈建议使用高分辨率计时器,这样您就不必测试尽可能多的迭代次数.请参阅CTimer使用QueryPerformanceCounter.

这是我的机器上的基线,10K迭代,高精度计时器

Sub TimeUDT()
   Dim i As Long
   Dim timer As New CTimer
   timer.StartCounter
   Dim participants(1 To 10000) As Participant
   For i = 1 To 10000
      participants(i).Name = "TestName"
      participants(i).Gender = 1
   Next
   Debug.Print "Elapsed time: " & timer.TimeElapsed & " ms"
End Sub

Elapsed time: 1.14359022404999 ms
Run Code Online (Sandbox Code Playgroud)

不管你信不信,你实际上在你的循环中获得对象创建的命中.在启动计时器之前,在循环中显式创建它们并查看差异:

之前

Sub TimeCls()
   Dim i As Long
   Dim timer As New CTimer
   Dim participants(1 To 10000) As New clsParticipant

   timer.StartCounter
   For i = 1 To 10000
      participants(i).Name = "TestName"
      participants(i).Gender = 1
   Next
   Debug.Print "Elapsed time: " & timer.TimeElapsed & " ms"
End Sub

Elapsed time: 24.9600996727434 ms
Run Code Online (Sandbox Code Playgroud)

Sub TimeCls()
   Dim i As Long
   Dim timer As New CTimer
   'Dim participants(1 To 10000) As New clsParticipant
   Dim participants(1 To 10000) As clsParticipant
   For i = 1 To 10000
       Set participants(i) = New clsParticipant
   Next i

   timer.StartCounter
   For i = 1 To 10000
      participants(i).Name = "TestName"
      participants(i).Gender = 1
   Next
   Debug.Print "Elapsed time: " & timer.TimeElapsed & " ms"
End Sub

Elapsed time: 4.66722880515984 ms
Run Code Online (Sandbox Code Playgroud)

这仅比基线慢4倍(在现在从测量中排除对象创建命中之后).如果进一步的声明iGendersName公开和直接变异它们,那么性能更接近底线,所以大部分的性能命中的其余部分是从Let间接.

Sub TimeCls()
   Dim i As Long
   Dim timer As New CTimer
   Dim participants(1 To 10000) As clsParticipant
   For i = 1 To 10000
       Set participants(i) = New clsParticipant
   Next i

   timer.StartCounter
   For i = 1 To 10000
      'participants(i).Name = "TestName"
      'participants(i).Gender = 1
      participants(i).sName = "TestName"
      participants(i).iGender = 1
   Next
   Debug.Print "Elapsed time: " & timer.TimeElapsed & " ms"
End Sub

Elapsed time: 1.71887815565976 ms
Run Code Online (Sandbox Code Playgroud)