【问题标题】:Why does VBA 100,000 cell For Each loop take so long?为什么每个循环的 VBA 100,000 单元格需要这么长时间?
【发布时间】:2020-12-27 11:33:16
【问题描述】:

更新:我知道有更快的方法来实现结果 - 我的问题是关于我的机器的相对性能。

我正在关注 Excel VBA 教程,其中讲师运行一个宏来创建一个新工作表,然后“For Each”循环遍历 100,000 个单元格(A1 到 A100000),在每个单元格中设置任意值(例如“Hello” )。当她执行宏时,需要

当我在自己的计算机上运行宏时,它需要很长时间(我没有计时,因为我通常会在沮丧中强制退出)。在循环中将代码从 100,000 个单元格更改为 10,000 个单元格,宏大约需要三分钟。

这是因为我使用的是旧计算机(和处理器)(Dell Optiplex 9020、8GB RAM、500GB HDD、Intel Core i5-4570 CPU @ ~3.2Ghz(4 个处理器))还是有其他可能的原因?

当宏运行时,任务管理器显示总 CPU 和内存利用率徘徊在 50% 左右,性能速度约为 3.4Ghz。

Sub Slow_code()
    Dim StartTime As Double
    Dim SecondsElapsed As Double
    Dim ShNew As Worksheet
    Dim cell As Range
    
    StartTime = Timer
      
    Application.StatusBar = "Wait"
    Set ShNew = Worksheets.Add
    For Each cell In ShNew.Range("A1:A10000")
        cell.Value = 10
    Next cell
    
    ShNew.Select
    Application.StatusBar = ""
        
    SecondsElapsed = Round(Timer - StartTime, 2)
    
    MsgBox "This code ran successfully in " & SecondsElapsed & " seconds", vbInformation
    
End Sub

找到罪魁祸首:停用插件包 (FastExcel v4),速度提高到与讲师和其他用户相当的水平。

【问题讨论】:

  • 你不需要循环。一行完成ShNew.Range("A1:A10000").Value = 10
  • 如果这只是一个测试然后尝试关闭事件、计算等然后检查?
  • 0.26s 在我 2 岁的笔记本电脑上。我建议你运行一些系统扫描/清理/重新安装你的操作系统或其他东西。
  • @scavenger 从字面上看,只是在我最近购买的翻新的前租赁设备上设置了窗口。除了我两天前安装的 Microsoft Office 外,它基本上是出厂重置。但是该设备至少有 7 年的历史
  • 您的 Intel i5-4570 还算不错,可以在 0.50 秒内处理(比我的快一半)。与您的戴尔相关的硬件/操作系统肯定存在一些问题。

标签: excel vba performance loops cpu


【解决方案1】:

在 VBA 中使用数组写入数据比在 for 循环中逐个添加要快得多。

在下面的示例中获得战利品

Sub ArrayFillRange()

'turning off screen updating makes calculations happen faster
    Application.ScreenUpdating = False

' Create Sheet    
    Set ShNew = Worksheets.Add

'   Fill a range by transferring an array
    Dim CellsDown As Long
    Dim i As Long
    Dim TempArray() As Double
    Dim TheRange As Range
 
'   Change these values
    CellsDown = 100000

'   Redimension temporary array
    ReDim TempArray(1 To CellsDown)
 
'   Set worksheet range
    Set TheRange = Range(Cells(1, 1), Cells(CellsDown, 1))
 
'   Fill the temporary array 
    For i = 1 To CellsDown
        TempArray(i) = 10
    Next i
 
'   Transfer temporary array to worksheet
    TheRange.Value = TempArray

'   Turning screen updating back on
    Application.ScreenUpdating = True

End Sub

顺便说一句,我不确定为什么您的代码在您的计算机上运行时间如此之长,而在我的计算机上运行时间为 0.34 秒。

如果您对速度差异感兴趣,请看下面,我已将两个选项(数组和 for 循环)的运行时间平均超过 5 次,行数越来越多。

您可以清楚地看到数组优于 for 循环。

【讨论】:

  • 谢谢,很高兴了解数组,但仍然不确定为什么我的代码运行如此缓慢
  • 关闭屏幕更新,看看它是否对您的代码有帮助。
  • 欣赏这一点。原来 Excel 插件正在干扰(FastExcel v4)。虽然现在我也知道将来要使用数组循环!
【解决方案2】:

每次设置一个值时,它都会重新计算工作表。

但是,您可以使用一个命令设置所有值,最终只需要重新计算一次。

Sub Fast_code()
Dim StartTime As Double
Dim SecondsElapsed As Double
Dim ShNew As Worksheet
Dim cell As Range

    StartTime = Timer
  
    Application.StatusBar = "Wait"
    Set ShNew = Worksheets.Add
    ShNew.Range("A1").Resize(10000,1).Value2 = 10

    ShNew.Select
    Application.StatusBar = ""
    
    SecondsElapsed = Round(Timer - StartTime, 2)

  MsgBox "This code ran successfully in " & SecondsElapsed & " seconds", vbInformation

End Sub 

有趣的是,下面的替换速度大约快了 3 倍

    ShNew.Range("A1").Resize(10000, 1).Value2 = Array(10)

我认为这是因为.Value.Value2 在使用范围内的多个单元格调用时期望一个数组。因此必须在内部进行更少的转化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-27
    • 2011-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多