[英]Are VBA Class module properties slow compared to accessing fields of User Defined Types?
我一直在嘗試使用類模塊開發一個宏,但是與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
和類模塊(名為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
首先,我強烈建議使用高分辨率計時器,這樣您就不必測試盡可能多的迭代次數。 請參閱使用QueryPerformanceCounter
CTimer 。
這是我的機器上的基線,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
不管你信不信,你實際上是在你的循環中獲得對象創建的命中。 在啟動計時器之前,在循環中顯式創建它們並查看差異:
之前
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
后
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
這僅比基線慢4倍(在現在從測量中排除對象創建命中之后)。 如果你進一步聲明你的iGender
和sName
公開的並且直接改變它們,那么性能甚至更接近基線,所以其余大部分性能命中來自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
他的答案中的Webb正確地強調了這樣一個事實:在您的測試中,您沒有考慮創建對象所需的時間,而是忘記添加對象的破壞。
下面代碼中的時間考慮了創建和銷毀時間,並且表明沒有任何東西是免費的,也就是說你不管怎么做,最后總時間大致相同。
我還添加了最后3個以三種不同方式顯式銷毀對象的函數,而不是將它留給垃圾收集器,時間保持不變。
我添加了這三個測試,因為我期待看到巨大的變化。 我記得很久以前我做過的測試,垃圾收集器只需要改變破壞順序10或100倍。 我無法在這里重現問題,可能是因為沒有那么多的對象或因為對象更簡單。 但是我添加了代碼只是為了顯示你應該做的另一個測試,如果你發現破壞所需的時間突然增加了。
這是我的代碼:
Sub Test()
Dim T0 As Single
T0 = timer
TimeCls_a
Debug.Print , timer - T0
T0 = timer
TimeCls_b
Debug.Print , timer - T0
T0 = timer
TimeCls_c
Debug.Print , timer - T0
T0 = timer
TimeCls_c_up
Debug.Print , timer - T0
T0 = timer
TimeCls_c_dn
Debug.Print , timer - T0
T0 = timer
TimeCls_c_all
Debug.Print , timer - T0
End Sub
Sub TimeCls_a()
Dim i As Long
Dim T0 As Single
Dim participants(1 To NCYCLES) As New clsParticipant
T0 = timer
For i = 1 To NCYCLES
participants(i).Name = "TestName"
participants(i).Gender = 1
Next
Debug.Print "TimeCls_a:", timer - T0
End Sub
Sub TimeCls_b()
Dim i As Long
Dim T0 As Single
Dim participants(1 To NCYCLES) As clsParticipant
For i = 1 To NCYCLES
Set participants(i) = New clsParticipant
Next i
T0 = timer
For i = 1 To NCYCLES
participants(i).Name = "TestName"
participants(i).Gender = 1
Next
Debug.Print "TimeCls_b:", timer - T0
End Sub
Sub TimeCls_c()
Dim i As Long
Dim T0 As Single
Dim participants(1 To NCYCLES) As clsParticipant
For i = 1 To NCYCLES
Set participants(i) = New clsParticipant
Next i
T0 = timer
For i = 1 To NCYCLES
participants(i).Name = "TestName"
participants(i).Gender = 1
Next
Debug.Print "TimeCls_c:", timer - T0
End Sub
Sub TimeCls_c_up()
Dim i As Long
Dim T0 As Single
Dim participants(1 To NCYCLES) As clsParticipant
For i = 1 To NCYCLES
Set participants(i) = New clsParticipant
Next i
T0 = timer
For i = 1 To NCYCLES
participants(i).Name = "TestName"
participants(i).Gender = 1
Next
For i = 1 To NCYCLES
Set participants(i) = Nothing
Next i
Debug.Print "TimeCls_c_up:", timer - T0
End Sub
Sub TimeCls_c_dn()
Dim i As Long
Dim T0 As Single
Dim participants(1 To NCYCLES) As clsParticipant
For i = 1 To NCYCLES
Set participants(i) = New clsParticipant
Next i
T0 = timer
For i = 1 To NCYCLES
participants(i).Name = "TestName"
participants(i).Gender = 1
Next
For i = NCYCLES To 1 Step -1
Set participants(i) = Nothing
Next i
Debug.Print "TimeCls_c_dn:", timer - T0
End Sub
Sub TimeCls_c_al()
Dim i As Long
Dim T0 As Single
Dim participants() As clsParticipant
ReDim participants(1 To NCYCLES)
For i = 1 To NCYCLES
Set participants(i) = New clsParticipant
Next i
T0 = timer
For i = 1 To NCYCLES
participants(i).Name = "TestName"
participants(i).Gender = 1
Next
ReDim participants(1 To NCYCLES)
Debug.Print "TimeCls_c_al:", timer - T0
End Sub
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.