简体   繁体   English

Excel VBA 宏速度不可预测地变慢,通常在 DoEvents

[英]Excel VBA macro slows down unpredictably, usually at DoEvents

What can be happening that slows down Excel to a crawl, sometimes for a minute or two, sometimes for hours, and its workload is spread across calls to DoEvents ?是什么导致 Excel 变得像爬行一样缓慢,有时是一两分钟,有时是几个小时,而且它的工作负载分散在对DoEvents的调用中?

Unfortunately, I can't post code because there seem to be no code causing the problem.不幸的是,我无法发布代码,因为似乎没有导致问题的代码。 It happens in different places without apparent pattern.它发生在不同的地方,没有明显的模式。 Below there are details about my investigation.下面是我的调查的详细信息。

Last week Excel on my computer started slowing down when running a macro that has been running without problems for years.上周 Excel 在我的电脑上运行一个已经运行多年没有问题的宏时开始变慢。 I tested the same macro on 2 other computers, but they don't seem to have the same problem.我在另外 2 台计算机上测试了相同的宏,但它们似乎没有相同的问题。 It's difficult to test because it doesn't always slow down and it never happens on the same place.很难测试,因为它并不总是减慢速度,也不会在同一个地方发生。 Sometimes it does it every minute, sometimes it works for 10 minutes and then it does it again.有时它每分钟执行一次,有时它会工作 10 分钟,然后再执行一次。 I tried two other computers for about 30 minutes and it never happened.我尝试了另外两台计算机大约 30 分钟,但从未发生过。

If I set breakpoints, it never slows down.如果我设置断点,它永远不会减速。

If I sprinkle prints it does, but never at the same place.如果我喷洒印花,它会喷洒,但绝不会喷洒在同一个地方。

If I press Ctrl+Break the macro stops after a few minutes, the debugger shows the current line highlighted as usual, but Excel keeps using 25% CPU (that is 100% of two cores).如果我按 Ctrl+Break 宏会在几分钟后停止,调试器会像往常一样突出显示当前行,但 Excel 会继续使用 25% 的 CPU(即两个内核的 100%)。 At this point every click on Excel or on the VBA IDE is responsive, but very slow.此时每次点击 Excel 或 VBA IDE 都有响应,但非常慢。 It usually takes minutes before you see the cursor moving to the clicked spot.您通常需要几分钟才能看到 cursor 移动到单击的位置。 Sometimes if you wait a few minutes the control comes back and it's possible to press F8 or F5 to continue the execution, but I usually kill Excel if the CPU usage doesn't go down in 2-3 minutes.有时,如果您等待几分钟,控件会返回,并且可以按 F8 或 F5 继续执行,但如果 Excel CPU 使用率在 2-3 分钟内没有下降,我通常会终止 go。

During the investigation I created this function:在调查期间,我创建了这个 function:

Sub DoEvents2()
  Dim T As Single
  T = Timer
  DoEvents
  Debug.Print Format(Timer - T, "0.000")
End Sub

and replaced the calls to DoEvents with calls to DoEvents2 , and I see on the debug window that the time required for the DoEvents is always a few thousands of a second, sometimes a few hundreds and once in a while, without apparent pattern, the time goes up.并将对DoEvents的调用替换为对DoEvents的调用,我在调试 window 上看到DoEvents2所需的时间始终是几千秒,有时是几百秒,偶尔,没有明显的模式,时间往上。 Often it goes up to ~90 seconds, sometimes less, a few times it lasted almost an hour, once it was still running the next day.通常它会上升到 90 秒左右,有时会更少,有几次它持续了将近一个小时,有一次它在第二天仍在运行。

Here is an example of the output on the debug window after running the macro with the above defined DoEvents2 :这是在使用上面定义的DoEvents2运行宏后调试 window 上的 output 的示例:

0.000
0.289
0.000
0.004
0.066
88.324
26.727
20.699
28.762
4.359
0.789
0.090
0.297
0.141
0.000
0.070
0.000
0.043
[...]
0.016
0.035
0.004
0.199
1.852
0.066
0.023
0.004
0.000
31.309
104.438
1.449
0.785
0.020
0.004
0.547
0.000
0.000
0.055

The macro is large and it's difficult to remove one piece without breaking it.宏很大,很难在不破坏它的情况下移除一块。

At first I thought the problem was with a form, but I removed all the forms and the problems is still there.起初我以为问题出在表格上,但我删除了所有 forms 问题仍然存在。

Then I tried working on volatile functions: I removed all the volatile functions and the problem is still there.然后我尝试处理 volatile 函数:我删除了所有 volatile 函数,但问题仍然存在。 Plus, it doesn't seem to be triggered by changes to Application.CalculationMode or Application.EnableEvents .另外,它似乎不是由Application.CalculationModeApplication.EnableEvents的更改触发的。

I checked if there are globals that could trigger long running garbage collection, but I didn't find anything.我检查了是否有全局变量可以触发长时间运行的垃圾收集,但我没有找到任何东西。 Plus, I don't see how garbage collection could run 12 hours (I left it running once the whole night and it was still there in the morning).另外,我不明白垃圾收集怎么能运行 12 个小时(我让它整晚运行一次,早上它还在那里)。

Sometimes I click on a button that runs a macro that uses JsonConverter , regular expressions, http requests, forms, volatile functions, etc., it runs for a minute or two as expected, and has no problems.有时我点击一个运行宏的按钮,该宏使用JsonConverter 、正则表达式、http 请求、forms、volatile 函数等,它按预期运行一两分钟,没有问题。 Then I click on another button that runs 10 lines of code, and it's done in a few hundreds of a second.然后我点击另一个运行 10 行代码的按钮,它在几百秒内完成。 I click the same button again and again, and after a few times Excel hangs.我一次又一次地单击同一个按钮,几次后 Excel 挂起。 I don't know where it hangs because it never hangs at the same line.我不知道它挂在哪里,因为它从不挂在同一条线上。

The problem started last week while Windows updates were going on, but I don't know if it's related.问题是上周Windows更新时出现的,不知道有没有关系。 Since then I've been working full time chasing this problem without success.从那时起,我一直在全职解决这个问题,但没有成功。

I can't post any code, because the macro has 14,000 lines, and it happens every where, wherever there is a DoEvents , even if it's a small 5 line function. But it seems to be affected by something that happened earlier.我不能发布任何代码,因为宏有 14,000 行,它发生在任何地方,只要有DoEvents ,即使它是一个小的 5 行 function。但它似乎受到更早发生的事情的影响。

So, my question is, what can be happening that slows down Excel to a crawl, sometimes for a minute or two, sometimes for hours, and its workload is spread across calls to DoEvents .所以,我的问题是,会发生什么事情会减慢 Excel 的速度,有时会持续一两分钟,有时会持续数小时,而且它的工作负载会分散到对DoEvents的调用中。

Edit编辑

It happened again about 40 minutes ago, I decided to let it vent hoping it would stop while I was working on something else.大约 40 分钟前它又发生了,我决定让它发泄,希望它能在我做其他事情时停止。 After 30 minutes I pressed Ctrl+Break to try to stop it, after a minute or two it did stop, then I did a burst of clicks on the save button of the VBA IDE, hoping that one of them would work and after a minute or two a popup showed asking if I wanted to save the file with unfinished calculation. 30 分钟后,我按 Ctrl+Break 试图停止它,一两分钟后它确实停止了,然后我对 VBA IDE 的保存按钮进行了一阵点击,希望其中一个可以工作,一分钟后或两个弹出窗口显示询问我是否要保存未完成计算的文件。 After a few seconds, while this popup was visible, the CPU usage went to zero.几秒钟后,虽然可以看到此弹出窗口,但 CPU 使用率变为零。 I asked to save the file without completing the calculation, it did (I can see the " - Saved" on the title bar), then the CPU went on sucking 2 cores with the IDE still showing the current line highlighted.我要求在不完成计算的情况下保存文件,它保存了(我可以在标题栏上看到“-已保存”),然后 CPU 继续吸取 2 个内核,IDE 仍然显示当前行突出显示。 I tried with a burst of clicks on the stop button, but didn't work (yet?).我尝试在停止按钮上点击一下,但没有用(还没有?)。

Edit 2编辑 2

I found a place in the macro where if I set a breakpoint and press F5 it works consistently, but if I remove the breakpoint it works once, then it hangs.我在宏中找到了一个位置,如果我设置一个断点并按 F5,它会始终如一地工作,但如果我删除断点它会工作一次,然后它会挂起。

This is the code:这是代码:

T0 = Timer
Debug.Print Application.CalculationState,
DoEvents ' Here I set the breakpoint
Debug.Print Application.CalculationState, Timer - T0

This is the output on the Immediate window after running it a few times with a breakpoint (you see the time it takes me to press F5 after seeing it stopping) and twice without the breakpoint.这是立即 window 上的 output 在运行几次断点后(你看到我在看到它停止后按 F5 所需的时间)和两次没有断点。 I am pasting a snapshot because I couldn't copy from a hanging Excel ready to be killed.我正在粘贴快照,因为我无法从挂起的 Excel 准备被杀死。 While that code is executed the calculation is manual and the events are disabled.在执行该代码时,计算是手动的,并且事件被禁用。 I don't think it was calculating.我不认为这是在计算。

在此处输入图像描述

Tomorrow I will try to reinstall Office.明天我将尝试重新安装 Office。

Edit 3编辑 3

Uninstalling and reinstalling Office didn't help.卸载并重新安装 Office 没有帮助。

But I think I found one factor that seems to reliably allow Excel to work without problems or to hang: the VPN.但我想我发现了一个似乎可以可靠地允许 Excel 正常工作或挂起的因素:VPN。

If I start Excel without VPN connection, then I can work without problems.如果我在没有 VPN 连接的情况下启动 Excel,那么我可以毫无问题地工作。 If I then start the VPN connection, the first click (and the following macro) has no problems, the second click is slow, the third one hangs and Excel needs to be killed.如果我然后启动 VPN 连接,第一次点击(和下面的宏)没有问题,第二次点击很慢,第三次挂起,Excel 需要被杀死。 Disconnecting the VPN after the second click doesn't help.第二次点击后断开 VPN 连接无济于事。 I tested this scenario 5-6 times, always with the same result.我对这种情况进行了 5-6 次测试,结果始终相同。

I can't think of any reason why Excel would be affected by the VPN connection.我想不出 Excel 会受到 VPN 连接影响的任何原因。 The only addins installed are the ones I am struggling with, they are on the local drive, no 3rd party addins installed.唯一安装的插件是我正在努力使用的插件,它们在本地驱动器上,没有安装第 3 方插件。 My macros do not access any.network drive.我的宏不访问任何网络驱动器。 There is one class with one member Req As New MSXML2.XMLHTTP60 which is never used during my tests.有一个 class 和一个成员Req As New MSXML2.XMLHTTP60在我的测试中从未使用过。

Edit 4编辑 4

Nope, nothing to do with the VPN.不,与 VPN 无关。 Today I'm in the office, without VPN, and the problem is still there.今天我在办公室,没有VPN,问题依然存在。

After reinstalling Office I had the same settings as before.重新安装 Office 后,我的设置与以前相同。

Is it possible to reset everything and make a new clean Office installation that doesn't remember anything from its previous life?是否有可能重置所有内容并制作一个新的干净的 Office 安装,不记得以前生活中的任何东西?

Here is a little update.这是一个小更新。 I don't know if this is the answer that allows to fix the problem, but it's the last thing I have tried before the problem disappeared.我不知道这是否是可以解决问题的答案,但这是我在问题消失之前尝试过的最后一件事。

Thinking that the file was corrupted, I started creating a new file, importing the code and the forms from the allegedly corrupted one, creating the sheets from scratch (rather than copying the old ones to avoid any risk of duplicating the corruption) and I realized that I had both one global variable and one sheet called ShNesting .认为文件已损坏,我开始创建一个新文件,从据称已损坏的文件中导入代码和表单,从头开始创建工作表(而不是复制旧文件以避免任何复制损坏的风险),我意识到我有一个全局变量和一张名为ShNesting表。 The duplicated names are not a problem because the global variable has narrower scope than the sheet object, so VBA never saw the sheet ShNesting .重复名称不是问题,因为全局变量的范围比工作表对象的范围更窄,因此 VBA 从未见过工作表ShNesting I checked on the git repository and I see that it has been working for 5 years with duplicated names without problems.我检查了 git 存储库,我发现它已经使用重复名称工作了 5 年没有问题。

I renamed the sheet to Sheet4 and the problem disappeared.我将工作表重命名为Sheet4 ,问题就消失了。

I tried to reproduce the problem with backup copies of the corrupted file, but I wasn't able to reproduce it.我试图用损坏文件的备份副本重现该问题,但我无法重现它。 I don't know if I wasn't able to reproduce it because the backup copies were saved in a condition that doesn't reproduce the problem and I wasn't able to recreate it, or if my computer decided to heal itself.我不知道我是否无法重现它,因为备份副本的保存条件不会重现问题并且我无法重现它,或者我的计算机是否决定自行修复。

I waited a few days, I never had the problem, so I thought to leave a little update here.我等了几天,我从来没有遇到过这个问题,所以我想在这里留下一点更新。

Not really a solution, but too long for comment.不是真正的解决方案,但评论太长了。
I know I've seen better stack tracing procedures, but maybe modify you're DoEvents2 and add a call to TraceRoutines at the top of all the UDF , SheetChange or whatever routines you think are running.我知道我见过更好的堆栈跟踪程序,但也许可以修改您的DoEvents2并在所有UDFSheetChange或您认为正在运行的任何例程的顶部添加对TraceRoutines的调用。 Use the Timeout on the TraceRoutines as a circuit breaker.TraceRoutines上的超时用作断路器。

Public DoingEvents As Boolean
Public TraceList As String
Public LastTime As Single
Public StartTime As Single

Sub DoEvents2()
    StartTime = Timer
    LastTime = StartTime
    If DoingEvents Then
        Debug.Print "Nested DoEvents calls?"
        TraceList = TraceList & "DoEvents" & " (@ " & Format(Timer - LastTime, "0.000") & "s)" & vbCrLf
        Debug.Assert False
    Else
        TraceList = vbNullString
    End If
    DoingEvents = True
    DoEvents
    DoingEvents = False
    Debug.Print Format(Timer - StartTime, "0.000") & " Doing Events"
    Debug.Print TraceList
End Sub

Sub TraceRoutines(Name As String, Optional Timeout As Long = 20)
'Static LastTime As Single
Static TimeoutTriggered As Boolean
    If Timeout = 0 Then TimeoutTriggered = True
    If DoingEvents Then
        TraceList = TraceList & Name & " (@ " & Format(Timer - LastTime, "0.000") & "s)" & vbCrLf
        LastTime = Timer
        If LastTime - StartTime > Timeout Then
            If Not TimeoutTriggered Then
                Debug.Print TraceList
                MsgBox "What is going on here?"
                Debug.Assert False
                TimeoutTriggered = True
            End If
        Else
            'Reset
            TimeoutTriggered = False
        End If
    End If
End Sub

Sub MyFunction()
    TraceRoutines "MyFunction"
End Sub

I have recently seen VBA code which exhibited very similar behaviour, that is it was code which had worked reliably for many years but then started to occasionally hang Excel. Eventually I isolated the problem to calls to Application.DoEvents that rather than taking the expected few milliseconds to execute could take up to three minutes.我最近看到 VBA 代码表现出非常相似的行为,即它是已经可靠工作多年但后来开始偶尔挂起 Excel 的代码。最终我将问题隔离到对Application.DoEvents的调用,而不是采取预期的少数几毫秒的执行时间最多可能需要三分钟。

The PCs in question had Netskope anti-virus installed and I discovered that the problem went away if Netskope was de-activated.有问题的 PC 安装了 Netskope 防病毒软件,我发现如果停用 Netskope,问题就会消失。 Though for me a permanent solution was to amend the code to no longer use DoEvents .尽管对我来说一个永久的解决方案是修改代码以不再使用DoEvents

So in answer to the question: Have you tried switching off any anti-virus?所以在回答这个问题时:您是否尝试过关闭任何防病毒软件?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM