【问题标题】:Range() VS Cells() - run timesRange() VS Cells() - 运行时间
【发布时间】:2016-03-18 00:13:59
【问题描述】:

我在这个站点上看到很多 VBA 代码使用 Range 方法和 For 循环:

Range("A" & i)

与正确的Cells 命令相反:

Cells(i,1)

我一直都知道Cells 方法更快,部分原因是Range 需要更长的时间来解决,部分原因是连接 (&) 是一个相对较慢的过程(与任何其他简单的算术运算相比 - AFAIK) .

那么,问题是,它真的更快吗?多少?有时,Range 格式更具可读性,尤其是对于新手而言。速度的提升是否证明了回复中的轻微不适和必要的额外解释是合理的?

【问题讨论】:

    标签: performance vba excel


    【解决方案1】:

    我做了一些测试,看看是什么。

    方法

    我测试了四种场景的速度。每个测试都包含一个执行 100 000 次循环的 For 循环。测试的核心是使用 with 语句来“抓取”一个单元格。

    For i = 1 To 100000
      With Cells(i, 1)
      End With
    Next i
    

    四个测试是:

    • 单元格,可变单元格 - With Cells(i, 1)

    • 细胞,单细胞 - With Cells(1, 1)

    • 范围,可变单元格 - With Range("A" & i)

    • 范围,单个单元格 - Range("A1")

    我为四个测试用例使用了单独的子程序,并使用了第五个子程序将它们中的每一个运行了 500 次。请参阅下面的代码。

    对于时间测量,我使用 GetTickCount 来获得毫秒精度。

    结果

    通过 500 次测量,结果非常一致。 (我已经用 100 次迭代多次运行它,结果几乎相同。)

              Cells     Cells     Range     Range
            (variable) (single) (variable) (single)
    avg       124,3     126,4     372,0     329,8
    median     125       125       374       328
    mode       125       125       374       328
    stdev      4,1       4,7       5,7       5,4
    min        109       124       358       327
    max        156       141       390       344
    

    解读

    Cells 方法比等效的 Range 方法快 2.6 倍。如果使用连接,这会增加 10% 的执行时间,这使得差异几乎是 3 倍。这是一个巨大的差异。

    另一方面,我们谈论的是平均 0.001 ms VS 0.004 ms 每个单元操作。除非我们在超过 2-30 万个单元上运行脚本,否则这不会产生明显的速度差异。

    结论

    是的,速度差异很大。

    不,我不会告诉人们使用 Cells 方法,除非他们处理大量细胞。

    测试设置

    • Win7 64 位
    • 8 GB 内存
    • 英特尔酷睿 i7-3770 @ 3.40 GHz
    • Excel 2013 32 位

    我错过了什么吗?我搞砸了什么吗?请不要犹豫指出来!干杯! :)

    代码

    Public Declare Function GetTickCount Lib "kernel32.dll" () As Long
    Sub testCells(j As Long)
      Dim i As Long
      Dim t1 As Long
      Dim t2 As Long
      t1 = GetTickCount
        For i = 1 To 100000
          With Cells(i, 1)
          End With
        Next i
      t2 = GetTickCount
      Sheet4.Cells(j, 1) = t2 - t1
    End Sub
    Sub testRange(j As Long)
      Dim i As Long
      Dim t1 As Long
      Dim t2 As Long
      t1 = GetTickCount
        For i = 1 To 100000
          With Range("A" & i)
          End With
        Next i
      t2 = GetTickCount
      Sheet4.Cells(j, 2) = t2 - t1
    End Sub
    Sub testRangeSimple(j As Long)
      Dim i As Long
      Dim t1 As Long
      Dim t2 As Long
      t1 = GetTickCount
        For i = 1 To 100000
          With Range("A1")
          End With
        Next i
      t2 = GetTickCount
      Sheet4.Cells(j, 3) = t2 - t1
    End Sub
    Sub testCellsSimple(j As Long)
      Dim i As Long
      Dim t1 As Long
      Dim t2 As Long
      t1 = GetTickCount
        For i = 1 To 100000
          With Cells(1, 1)
          End With
        Next i
      t2 = GetTickCount
      Sheet4.Cells(j, 4) = t2 - t1
    End Sub
    
    Sub runtests()
      Application.ScreenUpdating = False
      Application.Calculation = xlCalculationManual
      Dim j As Long
    
      DoEvents
      For j = 1 To 500
        testCells j
      Next j
    
      DoEvents
      For j = 1 To 500
        testRange j
      Next j
    
      DoEvents
      For j = 1 To 500
        testRangeSimple j
      Next j
    
      DoEvents
      For j = 1 To 500
        testCellsSimple j
      Next j
    
      Application.Calculation = xlCalculationAutomatic
      Application.ScreenUpdating = True
    
      For j = 1 To 5
        Beep
        DoEvents
      Next j
    
    End Sub
    

    【讨论】:

    • 干得好。你介意用Cells(i, "A") 之类的东西运行另一个测试吗?
    • 有趣,我现在就去做。谢谢! :)
    • @Ralph 它提出了 180 毫秒,这比原来的 Cells 解决方案要慢一些,但绝对比 Range 方法快。重新运行几次后,我将在明天更新我的答案。
    • 您能否将Range("A1").Offset(i-1,0)Cells(i,1) 进行比较。更快的应该是数组读取的范围。也许更好的基准是使用各种方法设置一个 1000×1000 的表格。
    • 通过我对使用值 Range("top").Offset(i,j) 填充表的测试产生 34,800 个单元/秒,Cells(i,j) 35,000 个单元/秒和内存阵列 1,780,500 个单元/秒。
    【解决方案2】:

    在看到.Cells(1, "A") 表示法的示例后,我扩展了测试,我认为这可能是.Range("A1") 的可读性与.Cells(1, 1) 的速度之间的良好平衡

    我测试了读取和写入,发现对于读取,.Cells(1, "A") 的执行时间大约是 .Range("A1") 的 69%,.Cells(1, 1) 的执行时间是 .Range("A1") 的一半。对于写入,差异较小(分别约为 88% 和 82%)。

    代码:

    Option Explicit
    Sub test()
    Dim i, x, y, a, t1, t2, t3, t4
    x=1000000
    y=x/100
    Debug.Print "---Read---" 'Cell A1 contains the number 55
    t1=Timer*1000
    For i = 1 to x
        a = Sheet1.Range("A1")
    Next
    t2=Timer*1000
    Debug.Print t2 - t1 & "ms"
    For i = 1 to x
        a = Sheet1.Cells(1, "A")
    Next
    t3=Timer*1000
    Debug.Print t3 - t2 & "ms (" & Round(100*(t3-t2)/(t2-t1),1)&"%)"
    For i = 1 to x
        a = Sheet1.Cells(1, "A")
    Next
    t4=Timer*1000
    Debug.Print t4 - t3 & "ms (" & Round(100*(t4-t3)/(t2-t1),1)&"%)"
    Debug.Print "---Write---"    
    a=55
    t1=Timer*1000
    For i = 1 to y
        Sheet1.Range("A1") = a
    Next
    t2=Timer*1000
    Debug.Print t2 - t1 & "ms"
    For i = 1 to y
        Sheet1.Cells(1, "A") = a
    Next
    t3=Timer*1000
    Debug.Print t3 - t2 & "ms (" & Round(100*(t3-t2)/(t2-t1),1)&"%)"
    For i = 1 to y
        Sheet1.Cells(1, "A") = a
    Next
    t4=Timer*1000
    Debug.Print t4 - t3 & "ms (" & Round(100*(t4-t3)/(t2-t1),1)&"%)"
    Debug.Print "----"
    End Sub
    

    ^手写,可能有错别字...

    平台:
    Excel 2013 32 位
    Windows 7 64 位
    16GB 内存
    至强 E5-1650 v2 @3.5GHz

    (编辑:在代码的编写部分将“x”更改为“y” - 请参阅手动输入代码的免责声明!)

    【讨论】:

      【解决方案3】:

      值得链接这个堆栈溢出问题,它进一步解释了如何提高性能:

      Slow VBA macro writing in cells

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-28
        • 2021-11-29
        • 2019-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多