【发布时间】:2022-10-05 18:58:44
【问题描述】:
我遇到了一个讨厌的 VBA 错误,它使Property Get 过程调用非常慢。这很可能是由于最近的 Office 更新(我有 Office365)。它只影响 32 位 CPU 上的 Excel。
错误
考虑一个名为Class1 的类,只有代码:
Option Explicit
Public Property Get Something() As Long: End Property
基本上,一个返回零的Get 属性。
运行以下代码时(在标准 .bas 模块中):
Public Sub TestSpeed()
Const iterations As Long = 10000
Dim i As Long
Dim t As Double
Dim coll As New Collection
\'
t = Timer
For i = 1 To iterations
coll.Add New Class1
CallGet coll.Item(coll.Count)
Next i
Debug.Print iterations & \" loops took \" & Round(Timer - t, 3) & \" seconds\"
End Sub
Sub CallGet(ByVal c As Class1)
Dim v As Variant
v = c.Something
End Sub
正如预期的那样,我得到了一个不错的时机:
但是,如果我在用于测试的属性的顶部添加一堆其他 Get 属性,那么情况就会发生变化。更新后的 Class1 可能如下所示:
Option Explicit
Public Property Get Something001() As Long: End Property
Public Property Get Something002() As Long: End Property
Public Property Get Something003() As Long: End Property
Public Property Get Something004() As Long: End Property
Public Property Get Something005() As Long: End Property
Public Property Get Something006() As Long: End Property
Public Property Get Something007() As Long: End Property
Public Property Get Something008() As Long: End Property
Public Property Get Something009() As Long: End Property
Public Property Get Something010() As Long: End Property
Public Property Get Something011() As Long: End Property
Public Property Get Something012() As Long: End Property
Public Property Get Something013() As Long: End Property
Public Property Get Something014() As Long: End Property
Public Property Get Something015() As Long: End Property
Public Property Get Something016() As Long: End Property
Public Property Get Something017() As Long: End Property
Public Property Get Something018() As Long: End Property
Public Property Get Something019() As Long: End Property
Public Property Get Something020() As Long: End Property
Public Property Get Something021() As Long: End Property
Public Property Get Something022() As Long: End Property
Public Property Get Something023() As Long: End Property
Public Property Get Something024() As Long: End Property
Public Property Get Something025() As Long: End Property
Public Property Get Something026() As Long: End Property
Public Property Get Something027() As Long: End Property
Public Property Get Something028() As Long: End Property
Public Property Get Something029() As Long: End Property
Public Property Get Something030() As Long: End Property
Public Property Get Something031() As Long: End Property
Public Property Get Something032() As Long: End Property
Public Property Get Something033() As Long: End Property
Public Property Get Something034() As Long: End Property
Public Property Get Something035() As Long: End Property
Public Property Get Something036() As Long: End Property
Public Property Get Something037() As Long: End Property
Public Property Get Something038() As Long: End Property
Public Property Get Something039() As Long: End Property
Public Property Get Something040() As Long: End Property
Public Property Get Something041() As Long: End Property
Public Property Get Something042() As Long: End Property
Public Property Get Something043() As Long: End Property
Public Property Get Something044() As Long: End Property
Public Property Get Something045() As Long: End Property
Public Property Get Something046() As Long: End Property
Public Property Get Something047() As Long: End Property
Public Property Get Something048() As Long: End Property
Public Property Get Something049() As Long: End Property
Public Property Get Something050() As Long: End Property
Public Property Get Something051() As Long: End Property
Public Property Get Something052() As Long: End Property
Public Property Get Something053() As Long: End Property
Public Property Get Something054() As Long: End Property
Public Property Get Something055() As Long: End Property
Public Property Get Something056() As Long: End Property
Public Property Get Something057() As Long: End Property
Public Property Get Something058() As Long: End Property
Public Property Get Something059() As Long: End Property
Public Property Get Something060() As Long: End Property
Public Property Get Something061() As Long: End Property
Public Property Get Something062() As Long: End Property
Public Property Get Something063() As Long: End Property
Public Property Get Something064() As Long: End Property
Public Property Get Something065() As Long: End Property
Public Property Get Something066() As Long: End Property
Public Property Get Something067() As Long: End Property
Public Property Get Something068() As Long: End Property
Public Property Get Something069() As Long: End Property
Public Property Get Something070() As Long: End Property
Public Property Get Something071() As Long: End Property
Public Property Get Something072() As Long: End Property
Public Property Get Something073() As Long: End Property
Public Property Get Something074() As Long: End Property
Public Property Get Something075() As Long: End Property
Public Property Get Something076() As Long: End Property
Public Property Get Something077() As Long: End Property
Public Property Get Something078() As Long: End Property
Public Property Get Something079() As Long: End Property
Public Property Get Something080() As Long: End Property
Public Property Get Something081() As Long: End Property
Public Property Get Something082() As Long: End Property
Public Property Get Something083() As Long: End Property
Public Property Get Something084() As Long: End Property
Public Property Get Something085() As Long: End Property
Public Property Get Something086() As Long: End Property
Public Property Get Something087() As Long: End Property
Public Property Get Something088() As Long: End Property
Public Property Get Something089() As Long: End Property
Public Property Get Something090() As Long: End Property
Public Property Get Something091() As Long: End Property
Public Property Get Something092() As Long: End Property
Public Property Get Something093() As Long: End Property
Public Property Get Something094() As Long: End Property
Public Property Get Something095() As Long: End Property
Public Property Get Something096() As Long: End Property
Public Property Get Something097() As Long: End Property
Public Property Get Something098() As Long: End Property
Public Property Get Something099() As Long: End Property
Public Property Get Something100() As Long: End Property
Public Property Get Something() As Long: End Property
新的时机非常糟糕:
笔记
通过更多的测试,我发现了以下内容:
- 如果我添加更多
Get属性,运行相同TestSpeed方法所需的时间会增加,但前提是我将它们添加到所用属性的顶部。当然,如果我删除一些程序,时间会减少。 - 它只影响我的 Excel 32 位版本。它在 Excel 64 位上运行良好,在 Word 等其他应用程序(32 位和 64 位)中也运行良好。我的 32 位和 64 位 Excel 都是 2102 版(内部版本 13801.21092),如 16.0.13801.21072 版
- 如果我通过替换使用后期绑定:
Sub CallGet(ByVal c As Class1)
和:Sub CallGet(ByVal c As Object)
错误消失了。当然后期绑定比早期绑定慢一点:问题
任何人都可以重现上述行为吗?
为什么会发生上述行为?
除了等待微软解决这个问题,我还能做些什么来解决这个问题吗?
编辑#1
正如@PeterT 在他的回答中所指出的那样,当与大量项目一起使用时,集合真的很慢,尤其是在通过索引检索项目时。
澄清一下,上述问题在使用数组或 Scripting.Dictionary 时仍然存在。例如,以下代码产生相同的问题:
Option Explicit Public Sub TestSpeed() Const iterations As Long = 10000 Dim i As Long Dim t As Double Dim arr() As Class1: ReDim arr(1 To iterations) \' t = Timer For i = 1 To iterations Set arr(i) = New Class1 CallGet arr(i) Next i Debug.Print iterations & \" loops took \" & Round(Timer - t, 3) & \" seconds\" End Sub Sub CallGet(ByVal c As Class1) Dim v As Variant v = c.Something End Sub使用数组更新时序:
编辑#2
显然,是否有多个
Property Get过程并不重要。即使该类只有一个属性,问题仍然存在,只是我没有注意到。通过连续按 F5 运行TestSpeed程序,我得到了以下结果:使用后期绑定,我得到了这些:
编辑#3
打开多个 Excel 实例(按下 ALT 键)时,所有新实例的问题都消失了,但初始实例却没有。但这仅当我在新的 Excel 文件中运行代码时。如果我只是打开一个已保存的已包含代码的 Excel 文件,那么问题在任何情况下仍然存在。
同样,如果我打开第一个 Excel 实例并在新的未保存文件中运行代码,那么问题就消失了。但是,当使用相同的代码打开任何保存的文件时,问题就会显现出来。
编辑#4
事实上,这个问题会影响所有应用程序(Word、Outlook、PPT),但它只有在文件被保存并重新打开时才会显现出来。我只在这些应用程序中运行代码而没有保存,因此错误地假设这只是一个 Excel 问题。
我也在 AutoCAD 2019 上进行了测试,即使加载保存的文件也没有问题。但是,AutoCAD 文件中没有嵌入 VBA 代码,而是另存为 \'.dvb\' 单独的项目文件。
保存没有代码的启用宏的文件(例如 xlsb/xlsm),然后打开并添加测试代码可以完美快速地工作 - 没问题。但是,如果在保存文件时有任何代码模块(即使是空白),那么在打开文件时添加测试代码时就会出现问题。
-
唔。我无法在 32 位中重现。 i.stack.imgur.com/aLuqX.png。 Excel 365,版本 16.0.13801.21072(可能落后于您的几个版本)。我也许可以稍后在单独的安装中进行测试。
-
@BigBen我刚刚注意到您的版本与我完全相同(也更新了问题)。这使我认为该问题可能与其他已安装的软件有关。
-
有趣 - 就像在插件中?那会比较烦人。
-
@BigBen 不确定。我所有的同事都有相同的版本和相同的问题,所以可能是插件或其他一些软件,如防病毒软件。
-
@BigBen 我已禁用所有插件,甚至在安全模式下运行 Excel,但问题仍然存在。绝对烦人。