Comparison of Dictionary, Collections and Arrays

前端 未结 4 1105
情深已故
情深已故 2020-11-30 21:10

I am trying to work out the relative benefits and features of dictionaries compared with collections and arrays.

I found an excellent article here but can\'t find a

4条回答
  •  暖寄归人
    2020-11-30 21:37

    With regards to the performance of collections versus dictionaries, I am finding that writing to dictionaries performs similarly to writing to collections, reading from a dictionary takes about twice as long as reading from a collection. Creating a dictionary in the first place is way slower than creating a collection.

    These are results I got for doing 100,000 iterations of reading from, writing to, and creating dictionaries/collections:

    Creating Multiple Dictionaries:   731ms
    Writing To Dictionary:            494ms
    Reading From Dictionary:           65ms
    
    Creating Multiple Collections:     29ms
    Writing To Collection:            459ms
    Reading From Collection:           26ms
    

    Note adding a reference to the Microsoft Scripting Runtine improves the speed of creating multiple dictionaries (to 495ms here).

    This is the code I used for testing this:

    Option Explicit
    
    Private p_lngTestCount As Long
    
    Sub SetUp()
      p_lngTestCount = 100000
    End Sub
    
    Sub TestAll()
      CreatingMultipleDictionaries
      WritingToDictionary
      ReadingFromDictionary
    
      CreatingMultipleCollections
      WritingToCollection
      ReadingFromCollection
    End Sub
    
    Sub CreatingMultipleDictionaries()
    
      Const sSOURCE As String = "CreatingMultipleDictionaries"
    
      Dim oPerfMon As CDevPerformanceMonitor
      Set oPerfMon = New CDevPerformanceMonitor
      Dim i As Long
      Dim dcTest As Dictionary
      SetUp
    
      Dim dblTimeElapsed As Double
      oPerfMon.StartCounter
    
      For i = 0 To p_lngTestCount
        'Set dcTest = CreateObject("Scripting.Dictionary")
        Set dcTest = New Dictionary
      Next i
    
      dblTimeElapsed = oPerfMon.TimeElapsed
    
      Debug.Print sSOURCE & ": " & p_lngTestCount & " iterations. " & vbCrLf & _
                  "Time elapsed: " & Round(dblTimeElapsed, 0) & "ms" & vbCrLf
    End Sub
    
    Sub CreatingMultipleCollections()
    
      Const sSOURCE As String = "CreatingMultipleCollections"
    
      Dim oPerfMon As CDevPerformanceMonitor
      Set oPerfMon = New CDevPerformanceMonitor
      Dim i As Long
      Dim colTest As Collection
      SetUp
    
      Dim dblTimeElapsed As Double
      oPerfMon.StartCounter
    
      For i = 0 To p_lngTestCount
        Set colTest = New Collection
      Next i
    
      dblTimeElapsed = oPerfMon.TimeElapsed
    
      Debug.Print sSOURCE & ": " & p_lngTestCount & " iterations. " & vbCrLf & _
                  "Time elapsed: " & Round(dblTimeElapsed, 0) & "ms" & vbCrLf
    End Sub
    
    Sub WritingToDictionary()
    
      Const sSOURCE As String = "WritingToDictionary"
    
      Dim oPerfMon As CDevPerformanceMonitor
      Set oPerfMon = New CDevPerformanceMonitor
      Dim i As Long
      Dim dcTest
      SetUp
    
      Set dcTest = CreateObject("Scripting.Dictionary")
      'Set dcTest = New Dictionary
    
      Dim dblTimeElapsed As Double
      oPerfMon.StartCounter
    
      For i = 0 To p_lngTestCount
       ' Performance about the same for both ways:
        dcTest.Item(CStr(i)) = "test"
        'dcTest.Add CStr(i), "test"
      Next i
    
      dblTimeElapsed = oPerfMon.TimeElapsed
    
      Debug.Print sSOURCE & ": " & p_lngTestCount & " iterations. " & vbCrLf & _
                  "Time elapsed: " & Round(dblTimeElapsed, 0) & "ms" & vbCrLf
    End Sub
    
    Sub WritingToCollection()
    
      Const sSOURCE As String = "WritingToCollection"
    
      Dim oPerfMon As CDevPerformanceMonitor
      Set oPerfMon = New CDevPerformanceMonitor
      Dim i As Long
      Dim colTest As Collection
      SetUp
    
      Dim dblTimeElapsed As Double
      Set colTest = New Collection
    
      oPerfMon.StartCounter
    
      For i = 0 To p_lngTestCount
        colTest.Add "test", CStr(i)
      Next i
    
      dblTimeElapsed = oPerfMon.TimeElapsed
    
      Debug.Print sSOURCE & ": " & p_lngTestCount & " iterations. " & vbCrLf & _
                  "Time elapsed: " & Round(dblTimeElapsed, 0) & "ms" & vbCrLf
    End Sub
    
    Sub ReadingFromDictionary()
    
      Const sSOURCE As String = "ReadingFromDictionary"
    
      Dim oPerfMon As CDevPerformanceMonitor
      Set oPerfMon = New CDevPerformanceMonitor
      Dim i As Long
      Dim dcTest
      SetUp
    
      Set dcTest = CreateObject("Scripting.Dictionary")
      'Set dcTest = New Dictionary
      dcTest.Add "key", "test"
    
      Dim stTest As String
      Dim dblTimeElapsed As Double
    
      oPerfMon.StartCounter
    
      For i = 0 To p_lngTestCount
        stTest = dcTest.Item("key")
      Next i
    
      dblTimeElapsed = oPerfMon.TimeElapsed
    
      Debug.Print sSOURCE & ": " & p_lngTestCount & " iterations. " & vbCrLf & _
                  "Time elapsed: " & Round(dblTimeElapsed, 0) & "ms" & vbCrLf
    End Sub
    
    Sub ReadingFromCollection()
    
      Const sSOURCE As String = "ReadingFromCollection"
    
      Dim oPerfMon As CDevPerformanceMonitor
      Set oPerfMon = New CDevPerformanceMonitor
      Dim i As Long
      Dim colTest As Collection
      SetUp
    
      Dim stTest As String
      Dim dblTimeElapsed As Double
      Set colTest = New Collection
      colTest.Add "test", "key"
    
      oPerfMon.StartCounter
    
      For i = 0 To p_lngTestCount
        stTest = colTest.Item("key")
      Next i
    
      dblTimeElapsed = oPerfMon.TimeElapsed
    
      Debug.Print sSOURCE & ": " & p_lngTestCount & " iterations. " & vbCrLf & _
                  "Time elapsed: " & Round(dblTimeElapsed, 0) & "ms" & vbCrLf
    End Sub
    

    Performance monitor class (CDevPerformanceMonitor):

    Option Explicit
    
    ' Performance monitoring used in logging
    ' See: https://stackoverflow.com/questions/198409/how-do-you-test-running-time-of-vba-code
    
    Private Type LARGE_INTEGER
      lowpart As Long
      highpart As Long
    End Type
    
    #If VBA7 Then
      Private Declare PtrSafe Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As LARGE_INTEGER) As Long
    #Else
      Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As LARGE_INTEGER) As Long
    #End If
    
    #If VBA7 Then
      Private Declare PtrSafe Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As LARGE_INTEGER) As Long
    #Else
      Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As LARGE_INTEGER) As Long
    #End If
    
    Private m_CounterStart As LARGE_INTEGER
    Private m_CounterEnd As LARGE_INTEGER
    Private m_crFrequency As Double
    
    Private Const TWO_32 = 4294967296#               ' = 256# * 256# * 256# * 256#
    
    Private Function LI2Double(LI As LARGE_INTEGER) As Double
      Dim Low As Double
      Low = LI.lowpart
      If Low < 0 Then
        Low = Low + TWO_32
      End If
      LI2Double = LI.highpart * TWO_32 + Low
    End Function
    
    Private Sub Class_Initialize()
      Dim PerfFrequency As LARGE_INTEGER
      QueryPerformanceFrequency PerfFrequency
      m_crFrequency = LI2Double(PerfFrequency)
    End Sub
    
    Public Sub StartCounter()
      QueryPerformanceCounter m_CounterStart
    End Sub
    
    Public Function PerformanceCount() As Double
      Dim liPerformanceCount As LARGE_INTEGER
      QueryPerformanceCounter liPerformanceCount
      PerformanceCount = LI2Double(liPerformanceCount)
    End Function
    
    Public Function MicroTime() As Double
      MicroTime = Me.PerformanceCount * 1000000# / m_crFrequency
    End Function
    
    Public Property Get TimeElapsed() As Double
      Dim crStart As Double
      Dim crStop As Double
      QueryPerformanceCounter m_CounterEnd
      crStart = LI2Double(m_CounterStart)
      crStop = LI2Double(m_CounterEnd)
      TimeElapsed = 1000# * (crStop - crStart) / m_crFrequency
    End Property
    

提交回复
热议问题