Excel 在VBA中加速嵌套循环宏所需的指针

Excel 在VBA中加速嵌套循环宏所需的指针,excel,vba,Excel,Vba,我需要帮助加速我的简单、8变量、嵌套循环宏。每个循环仍然需要约1秒的时间,并且需要几十万个循环才能完成,因此需要3到4天才能完成!从我在这里的阅读和实验中,我已经尽我所能地简化了,但是现在我遇到了困难 我的宏基本上有3个段。1) 为每个循环上的变量赋值,2)将这些值插入我的excel模型以执行计算,3)每次都将每次迭代的结果粘贴到新行上。我已经对每个段进行了计时,每个段所需的时间(大约)分别为0.4s、0.4s和0.2s 我对第1)段最为困惑,因为它只需要0.4s就可以为每个循环上的变量赋值。我

我需要帮助加速我的简单、8变量、嵌套循环宏。每个循环仍然需要约1秒的时间,并且需要几十万个循环才能完成,因此需要3到4天才能完成!从我在这里的阅读和实验中,我已经尽我所能地简化了,但是现在我遇到了困难

我的宏基本上有3个段。1) 为每个循环上的变量赋值,2)将这些值插入我的excel模型以执行计算,3)每次都将每次迭代的结果粘贴到新行上。我已经对每个段进行了计时,每个段所需的时间(大约)分别为0.4s、0.4s和0.2s

我对第1)段最为困惑,因为它只需要0.4s就可以为每个循环上的变量赋值。我承认第2部分的缓慢是因为我的excel电子表格有5000行(可能是我糟糕的excel编程),第3部分已经被重组(感谢你们在这个论坛上!),并且比以前快得多

代码如下:

Sub VariableIteration2()
Dim a As Double
Dim b As Double
Dim c As Double
Dim d As Double
Dim w As Double
Dim x As Double
Dim y As Double
Dim z As Double
Dim Row As Long
Dim Results As Variant
Dim T1S As Double
Dim T1E As Double
Dim T2S As Double
Dim T2E As Double
Dim T3S As Double
Dim T3E As Double
Dim T4S As Double
Dim T4E As Double
Dim V1S As Double
Dim V1E As Double
Dim V2S As Double
Dim V2E As Double
Dim V3S As Double
Dim V3E As Double
Dim V4S As Double
Dim V4E As Double
Dim ST1 As Double
Dim ST2 As Double
Dim ST3 As Double
Dim ST4 As Double
Dim SV1 As Double
Dim SV2 As Double
Dim SV3 As Double
Dim SV4 As Double
Dim Startime As Single
Row = 18
T1S = Range("S3").Value
T1E = Range("S4").Value
T2S = Range("t3").Value
T2E = Range("t4").Value
T3S = Range("u3").Value
T3E = Range("u4").Value
T4S = Range("v3").Value
T4E = Range("v4").Value
V1S = Range("s6").Value
V1E = Range("s7").Value
V2S = Range("t6").Value
V2E = Range("t7").Value
V3S = Range("u6").Value
V3E = Range("u7").Value
V4S = Range("v6").Value
V4E = Range("v7").Value
ST1 = Range("s5").Value
ST2 = Range("t5").Value
ST3 = Range("u5").Value
ST4 = Range("v5").Value
SV1 = Range("s8").Value
SV2 = Range("t8").Value
SV3 = Range("u8").Value
SV4 = Range("v8").Value

‘SEGMENT_1_ASSIGNING_VALUES   
Startime = Timer
For a = V1S To V1E Step SV1
    For w = T1S To T1E Step ST1
        For b = V2S To V2E Step SV2
            For x = T2S To T2E Step ST2
                For c = V3S To V3E Step SV3
                    For y = T3S To T3E Step ST3
                        For d = V4S To V4E Step SV4
                            For z = T4S To T4E Step ST4
                            Range("dy20") = Timer - Startime
‘SEGMENT_2_PASTE_VARIABLES_INTO_CALCULATIONS
                             Startime = Timer
                                Range("s19").Value = w
                                Range("s20").Value = a
                                Range("t19").Value = x
                                Range("t20").Value = b
                                Range("u19").Value = y
                                Range("u20").Value = c
                                Range("v19").Value = z
                                Range("v20").Value = d
                                Range("s23:v24").Value = Range("s19:v20").Value
                             Range("dy21") = Timer - Startime
‘SEGMENT_3_RECORD_RESULTS
                             Startime = Timer
                                    Row = Row + 1
                                    Results = Range("g15:ax15")
                                    Range(Cells(Row, 131), Cells(Row, 131 + UBound(Results, 2) - 1)) = Results
                             Range("dy22") = Timer - Startime
                            Next z
                        Next d
                    Next y
                Next c
            Next x
        Next b
    Next w
Next a

End Sub

非常感谢您的帮助。

屏幕更新和自动计算会降低性能


详细说明了这一点。

屏幕更新和自动计算会降低性能


这一点已详细解释。

请记住,每次移动/分配工作表上的单元格值时,Excel都会停止并重新计算整个工作表@Joe提供的在移动数据时关闭自动计算的链接将提高速度。但是

如果您在VBA例程中执行所有计算,而不是将它们复制到工作表并依靠公式执行计算,则循环速度将大大加快。此外,使用基于内存的数组保存结果可以最大限度地减少例程对此副本的速度减慢。(奇普·皮尔森有一个

因此,我的建议是:

  • 使用循环变量(w、a、x等)在VBA例程中执行计算,即将公式移动到代码中
  • 将结果以双精度存储在内存数组中
    Dim结果(1到44)
  • 将该结果数组直接复制到结果范围的下一个区域(g15:ax15)
  • 或者更好的方法是,将此结果数组附加到另一个内存数组
    Dim allResults(1到1000,1到44)作为Double
    --(提示:不能在一条语句中执行此操作,必须循环以从结果数组复制到allResults数组中的下一个插槽)。然后将allResults数组块复制到工作表上的某个范围

  • 这些技术应该会大大提高速度。

    请记住,每次在工作表上移动/指定单元格时,Excel都会停止并重新计算整个工作表@Joe提供的在移动数据时关闭自动计算的链接将提高速度。但是

    如果您在VBA例程中执行所有计算,而不是将它们复制到工作表并依靠公式执行计算,则循环速度将大大加快。此外,使用基于内存的数组保存结果可以最大限度地减少例程对此副本的速度减慢。(奇普·皮尔森有一个

    因此,我的建议是:

  • 使用循环变量(w、a、x等)在VBA例程中执行计算,即将公式移动到代码中
  • 将结果以双精度存储在内存数组中
    Dim结果(1到44)
  • 将该结果数组直接复制到结果范围的下一个区域(g15:ax15)
  • 或者更好的方法是,将此结果数组附加到另一个内存数组
    Dim allResults(1到1000,1到44)作为Double
    --(提示:不能在一条语句中执行此操作,必须循环以从结果数组复制到allResults数组中的下一个插槽)。然后将allResults数组块复制到工作表上的某个范围

  • 这些技术应该可以大大提高速度。

    在设置属性或调用方法时,每种方法都是CPU中的函数调用。这意味着堆栈设置开销。函数调用比内联代码慢。出于同样的原因,在VBA中使用循环而不是函数

    首先,不要反复指定所有这些属性。除非你改变它们,否则它们不会改变

    With Selection.Find
        .ClearFormatting
        .Replacement.ClearFormatting
        .Forward = True
        .Wrap = wdFindContinue
        .Format = False
        .MatchCase = False
        .MatchWholeWord = False
        .MatchByte = False
        .MatchAllWordForms = False
        .MatchSoundsLike = False
        .MatchWildcards = False
        .MatchFuzzy = False
    
        For loop to go through each word pair
            .Text = SrcText
            .Replacement.Text = DestText
            .Find.Execute Replace:=wdReplaceAll
        Next
    
    End With
    
    最小化圆点

    因此,如果您对性能感兴趣,请最小化点(每个点都是一个查找),尤其是在循环中

    有两种方法。一种方法是,如果要多次访问,则将对象设置为最低的对象

    eg(较慢)

    (更快,因为每次使用对象时都会忽略一个点)

    第二种方法是使用。一次只能有一个处于活动状态

    这跳过了100次查找

    with wsheet
    For x = 1 to 100
     msgbox .name
    Next
    end with
    
    字符串压缩

    不要一次连接一个字符的字符串。使用字符串时,先使用小字符串,然后使用现在更大的字符串。您可以使用类似字符串生成器的
    MID
    语句(而不是
    MID
    函数)

    读取属性

    不要重新读取未更改的属性,尤其是在进程外或后期绑定时。将它们放入一个变量中。读取变量比对象查找(也是一个函数调用,如果后期绑定,至少两个)和函数调用更快

    变量

    常量和文本在编译后基本相同

    Const x = 5
    msgbox x
    

    msgbox 5
    
    文本直接插入到代码中。字符串和对象变量具有管理器,这会产生开销。避免无缘无故地创建变量。这是一个无意义且缓慢的变量示例

    x = "This is a string"
    msgbox x
    
    相比

    const x = "This is a string"
    msgbox x
    

    对象类型

    这里有两个概念-进程内或进程外和早期或晚期绑定

    EXE文件连接到进程外。A.
    x = "This is a string"
    msgbox x
    
    const x = "This is a string"
    msgbox x
    
    msgbox "This is a string"