Excel VBA在执行循环时考虑如何能够尽可能地节省资源,增加效率

很多Excel VBA文章和图书都介绍过如何优化VBA代码,使代码运行得更快。一些使Excel VBA代码运行更快的技术和技巧,与大家分享。

使用For Each…Next循环

可以使用For Each…Next循环来保证程序代码更快地执行。在使用For Each…Next循环时,对于存储在集合或数组中的每个对象执行一组语句,程序更简洁,也更容易阅读、调试和维护。当For Each…Next语句迭代集合时,自动指定一个对集合当前成员的引用,然后在到达集合的尾部时跳出循环语句。

与使用计数进行循环相比,在遍历集合或数组时使用For Each…Next循环将更快。在多数情况下,使用For Each…Next循环也更方便,并且使您的宏更简洁、更容易阅读和调试。

下面的示例运行很慢,因为在每次循环重复时它设置并调用了行变量.Row(i)。

Sub DoSomethingSlow()

Dim Start As Double, Finish As Double

Start = Timer

'--------------------------------------

Dim Cell As Range, i As Long

With Sheet1.Range("A1:A10000")

For i = 1 To 10000

Set Cell = .Rows(i)

If Cell > 0 Then

Cell.Font.ColorIndex = 5

End If

Next

End With

'--------------------------------------

Finish = Timer

MsgBox "本次运行的时间是" & Finish - Start

End Sub

下面的示例代码更简洁,其运行速度大约是上面代码的2~3倍。因为For Each…Next循环自动记录行数并定位,而不需要调用变量i。

Sub DoSomethingFaster()

'快两至三倍

Dim Start As Double, Finish As Double

Start = Timer

'--------------------------------------

Dim Cell As Range

With Sheet1

For Each Cell In .Range("A1:A10000")

If Cell > 0 Then

Cell.Font.ColorIndex = 5

End If

Next

End With

'--------------------------------------

Finish = Timer

MsgBox "本次运行的时间是" & Finish - Start

End Sub

在执行循环时考虑如何能够尽可能地节省资源

(1)分析循环以查看是否正在不必要地执行一些消耗内存的重复操作。例如,是否可以在循环外(而不是在循环中)设置某些变量?每次都通过循环执行的转换过程是否可以在循环之外执行?

(2)考虑是否必须在满足特定的条件时才执行循环。如果是,也许可以更早地退出循环。例如,假设正在对一个不应该包含数字字符的字符串进行数据验证。如果循环要检查字符串中的每个字符以确定其中是否包含数字字符,那么您可以在找到第一个数字字符时立即退出循环。

(3)如果必须在循环中引用数组的元素,可以创建一个临时变量存储该元素的值,而不是引用数组中的值。从数组中检索值比从相同类型的变量读取值要慢。

(4) 将属性和方法放在循环外部

在代码运行时,获取变量的值快于获取属性的值。因此,如果您的代码在循环内部获取属性的值,您可以在循环外部将该属性的值先指定给一个变量,然后在循环内部使用此变量代替属性的值,这样的代码将运行得更快。

下面所示的代码运行较慢,因为在每次重复循环时都必须获取Sheet的Range属性的值。

Sub TryThisSlow()

Dim Start As Double, Finish As Double

Start = Timer

'--------------------------------------

Dim MyLoop As Long

For MyLoop = 2 To 4001

Cells(MyLoop, 2) = Sheet1.Range("B1")

Next

'--------------------------------------

Finish = Timer

MsgBox "本次运行的时间是" & Finish - Start

End Sub

下面的示例与上面所产生的结果相同,但比上面的要更快,因为在循环开始以前我们已经将Sheet的Range属性的值指定给了单独的变量MyVar。这样,代码将在每次重复循环时利用该变量的值,而不必每次都要调有属性。

Sub TryThisFaster()

'快约35%以上

Dim Start As Double, Finish As Double

Start = Timer

'--------------------------------------

Dim MyVar As String, MyLoop As Long

MyVar = Sheet1.Range("B1")

For MyLoop = 2 To 4001

Cells(MyLoop, 2) = MyVar

Next

'--------------------------------------

Finish = Timer

MsgBox "本次运行的时间是" & Finish - Start

End Sub

如果您在一个循环内部使用多个对象访问,您也可以使用With…End With将您能够移动的对象移到循环外部。下面的示例在每次循环重复时都调用Sheets对象和Cells属性。

Sub NowTryThisSlow()

Dim Start As Double, Finish As Double

Start = Timer

'--------------------------------------

Dim c As Long

For c = 1 To 8000

Sheet1.Cells(c, 5) = c

Next

'--------------------------------------

Finish = Timer

MsgBox "本次运行的时间是" & Finish - Start

End Sub

对上面的代码改写如下,使用With语句将调用Sheets对象移到循环外部,只剩余调用Cells。

Sub NowTryThisFaster()

'约快3倍

Dim Start As Double, Finish As Double

Start = Timer

'--------------------------------------

Dim c As Long

With Sheet1

For c = 1 To 8000

.Cells(c, 5) = c

Next

End With

'--------------------------------------

Finish = Timer

MsgBox "本次运行时间为" & Finish - Start

End Sub

注:您也能通过使用对象变量在循环外部调用该对象。

关于带有特定目的的VBA方法的更多的信息,您可参见VBA帮助系统相关主题。

结语

当然,代码优化可能不是绝对必要的,这依赖于您要做的工作……如果您正好编写了一个快速且简短的或者是一次性使用且与速度和/或简洁要求无关的代码,您就不需要优化代码。

但另一方面,如果您处理一个带有很多数据、工作簿、工作表等大的工程,再次检查您第一次编写好的代码,看看是否您的代码需要优化,而这样做总是值得的。

最终,您将养成编写代码的好习惯,将会使您的代码更简洁、运行更快速、并且容易为您自已和他人阅读和调试。同时,由于您的代码简洁,因而输入更快,工作效率更高。

举报
评论 0