【发布时间】:2020-01-23 13:41:09
【问题描述】:
为简洁/正确而编辑:滚动到末尾以获取 TL/DR
我运行了一个相当长的宏,它从 Workspace/Sharepoint 打开一堆文件,将内容复制到我的 Excel 工作表中,将数据加载到数组中,比较数组条目,将数据写入工作表等。它使用 PowerPivot 和 Power Query 以及在多个工作簿的多个工作表中读取/写入内容。
在寻找代码优化选项期间,我发现使用以下行激活工作表可使我的代码运行速度提高 3 倍。我想弄清楚为什么以及如何,以避免将来出现这种减速。
ThisWorkbook.Sheets("Dashboard").Activate
我还将“仪表板”更改为另一个新添加的完全空的工作表 (sheets(15)),这对运行时间没有影响,这意味着它的速度不会快 3 倍。我认为,在活动工作表上工作会产生一些影响。但是不,激活新的、空的和未使用的工作表并没有使代码更快。我使用以下宏增强功能:
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
我不在代码中的其他任何地方使用 .activate。 (我专门cntrl + f'ed)。 .activate 就在一个冗长的 For-Loop 之前,它调用了 3 个其他潜艇。在下图中,您可以看到 For-Loop 的运行时间。
See the image for some run times in seconds
图中的开始是指分配一些变量等所花费的时间。工具、序列号和其他是循环期间运行的子程序。这些数字是循环期间所有步骤的总和,循环主要有大约 300 步,可能需要从 0 到 0.3 秒。
以下是部分代码。我将发布 For-Loop 和“check_others”子以及它调用的子。那是最短的潜艇,但正如您在上图中看到的那样,即使那个潜艇也受到影响,所以发生的事情似乎不仅仅影响一个潜艇。为了便于阅读,我还去掉了计时循环的代码。
'Go from first row of the Prisma report to the last row. (Reference WITHIN the pivot table. e.g: 1 is absolut row 6)
RowCount = ThisWorkbook.Sheets("Prisma").PivotTables("OperationData").DataBodyRange.Rows.Count
PrismaArr = ThisWorkbook.Sheets("Prisma").Range("H6:U" & RowCount + 5)
'It is unclear why and how but without this line, the code takes 3x longer to execute.
ThisWorkbook.Sheets("Dashboard").Activate
For Prismarow = 1 To RowCount
'Set some of the most used variables and progres bar. (Indicator, Comment, Instruction)
progress 13 + (Prismarow / RowCount) * 82, "Analizing"
IndicatorSkipFurtherAnalyses = 0
CommentToBeAnalysed = PrismaArr(Prismarow, 5)
InspectionInstruction = PrismaArr(Prismarow, 6)
'#7 G - Check Tools
Call Check_Tools(PrismaArr, Prismarow, CommentToBeAnalysed, InspectionInstruction)
'#8 H - Check serial numbers
If Not IndicatorSkipFurtherAnalyses Like "1" Then _
Call Check_Serial_Numbers(PrismaArr, Prismarow, CommentToBeAnalysed, InspectionInstruction)
'#9 I - Check for others (everything else)
If Not IndicatorSkipFurtherAnalyses Like "1" Then _
Call Check_Others(PrismaArr, Prismarow, CommentToBeAnalysed, InspectionInstruction)
SkipThisEntry:
Next
调用 Check_Others(PrismaArr、Prismarow、CommentToBeAnalysed、InspectionInstruction):
Sub Check_Others(ByVal PrismaArr, ByVal Prismarow As Long, ByVal CommentToBeAnalysed As String, ByVal InspectionInstruction As String)
'Check if the entry was already deleted, ignore it otherwise
If Not PrismaArr(Prismarow, 7) Like "E D" Then
'Check that all entries on the PDF which are not tools or serial numbers are empty
If PrismaArr(Prismarow, 13) Like "2" And PrismaArr(Prismarow, 10) Like "FALSCH" And PrismaArr(Prismarow, 11) Like "FALSCH" Then
If Not CommentToBeAnalysed Like "" Then
Call Fill_Out_Others_Analysis(PrismaArr, Prismarow, CommentToBeAnalysed, InspectionInstruction, 5)
End If
End If
'Check if there should have been a serial number here
If PrismaArr(Prismarow, 10) Like "WAHR" And CommentToBeAnalysed Like "" Then
Call Fill_Out_Others_Analysis(PrismaArr, Prismarow, CommentToBeAnalysed, InspectionInstruction, 19)
End If
'Check if there should have been a tool number here
If PrismaArr(Prismarow, 11) Like "WAHR" And CommentToBeAnalysed Like "" Then
Call Fill_Out_Others_Analysis(PrismaArr, Prismarow, CommentToBeAnalysed, InspectionInstruction, 18)
End If
End If
End Sub
调用 Fill_Out_Others_Analysis(PrismaArr, Prismarow, CommentToBeAnalysed, InspectionInstruction, 5):
Sub Fill_Out_Others_Analysis(ByVal PrismaArr, _
ByVal Prismarow As Long, _
ByVal CommentToBeAnalysed As String, _
ByVal InspectionInstruction As String, _
ByVal Error_Code As String)
'Write the given information into the analysis sheet
With ThisWorkbook.Sheets("Analysis").ListObjects("Analysis_Others").ListRows.Add
.Range.ClearFormats
.Range(1, 1) = PrismaArr(Prismarow, 1)
.Range(1, 2) = Prismarow + 5 & " (" & PrismaArr(Prismarow, 2) & ")"
.Range(1, 3) = CommentToBeAnalysed
.Range(1, 4) = InspectionInstruction
.Range(1, 6) = "----"
.Range(1, 7) = "----"
.Range(1, 8) = "----"
.Range(1, 9) = "----"
.Range(1, 10) = "----"
.Range(1, 11) = "----"
'Assign errors, including coloring and statistical error assignment
Call AssignError(Error_Code, .Range)
End With
End Sub
此时它调用“AssignError”,它太长而无法真正发布。但即使我注释掉那个调用,宏仍然可以通过使用 .activate 来加速。
同样,如果我启动宏,然后在打开和关闭 Excel 表以收集数据时,但在 For-Loop 开始之前,单击退出 excel,我也可以类似地加速宏。我只需单击 Windows 按钮并让开始菜单保持打开状态,同时我会看到进度条以比平时快 3 倍的速度填满。事实上,这具有更好的性能,即使在我使用 .activate 时也可以将程序速度提高约 20% (16s->13s)。这并不让我感到惊讶。但是对于 .activate 行为,我根本没有解释。
有人能理解吗?
TL/DR: 有没有人知道宏中间的 worksheet.activate 如何可能将执行速度提高 3 倍。即添加 worksheet.activate 使我的代码在 1/3 的时间内完成运行。
谢谢 丹尼斯
【问题讨论】:
-
来看看
For -
感谢您的关注,我提供了更多信息。希望它不会太混乱。
-
我的想法是这与加载工作表准备写入它有关,但您的代码甚至不会写入或读取仪表板。可能与在进程队列中赋予它更高的优先级有关,但老实说,这几乎只是在黑暗中刺伤。
-
是的,这就是我尝试新的/空的工作表的原因之一。你知道另一种测试方法吗?有没有办法强制更高的优先级来测试另一个假设? (我不确定你指的是什么,我只知道windows中的优先级设置,而不是excel中的)
-
如果您改为激活“prisma”会发生什么?