Отредактировано для краткости / правильности: прокрутите до конца для TL / DR
Я запускаю довольно длинный макрос, который открывает кучу файлов из Workspace / Sharepoint, копирует вещи в мой лист Excel, загружает данные в массивы, сравнивает записи массива, записывает данные в таблицы и т. д. c. Он использует PowerPivot и Power Query и читает / записывает данные на нескольких листах в нескольких книгах.
Во время поиска вариантов оптимизации кода я обнаружил, что активация листа со следующей строкой ускорила мой код в 3 раза. Я хотел бы выяснить, почему и как, чтобы избежать таких замедлений в будущем.
ThisWorkbook.Sheets("Dashboard").Activate
Я также изменил «Панель инструментов» на другую, недавно добавленную, полностью пустой лист (листов (15)), и это не повлияло на время выполнения, то есть не в 3 раза быстрее. Я думал, что работа над активным листом имеет некоторый эффект. Но нет, активация нового, пустого и неиспользованного листа не делала код быстрее. Я использую следующие улучшения макросов:
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Я не использую .activate где-нибудь еще в коде. (Я специально назвал это Ctrl +). .Activate находится прямо перед длинным For-L oop, который вызывает 3 других сабвуфера. На следующем рисунке вы можете увидеть время работы For-L oop.
См. Изображение для некоторых времен выполнения в секундах
В начале изображения указано время, необходимое для присвоения некоторых переменных и т. Д. c .. Инструменты, серийные номера и другие подводные лодки во время л oop. Эти числа являются суммой всех шагов в течение l oop, l oop в основном имеет около 300i sh шагов, которые могут занять от 0 до 0,3 с.
Следующее является частью кода , Я опубликую For-L oop и подпрограмму "check_others", а также подпрограммы, которые она вызывает. Это самый короткий сабвуфер, но, как вы можете видеть на картинке выше, даже этот саб выполняется, поэтому то, что происходит, не оказывает влияния только на один саб. Для удобства чтения я также избавился от кода, который синхронизировал вызов l oop.
'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
Call 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
Call 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-L oop нажмите кнопку Excel. Я просто нажимаю на кнопку windows и оставляю меню пуска открытым, пока наблюдаю, как мой индикатор заполнения заполняется в 3 раза быстрее, чем обычно. На самом деле, это дает еще лучшую производительность, ускоряя программу, даже когда я использую .activate на дополнительные 20% (16-> 13s). Это меня совсем не удивляет. Но для поведения .activate у меня просто нет объяснения.
Может ли кто-нибудь это понять?
TL / DR: Кто-нибудь знает, как worksheet.activate в середине макроса может ускорить выполнение? т. е. в 3 раза. То есть добавление worksheet.activate приводит к тому, что мой код работает sh, что выполняется за 1/3 времени, которое требуется в противном случае.
Спасибо, Денис