Почему активация указанных c листов влияет на время выполнения моего макроса - PullRequest
4 голосов
/ 23 января 2020

Отредактировано для краткости / правильности: прокрутите до конца для 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 времени, которое требуется в противном случае.

Спасибо, Денис

Ответы [ 2 ]

4 голосов
/ 30 января 2020

У меня есть несколько идей, но я тоже ловлю рыбу.

1) Graphi c обновление все еще происходит. Даже если вы установили Application.ScreenUpdating в False, может ли это быть, что он все еще обновляет / отслеживает графику при обновлении ячеек в подпрограмме Fill_Out_Others_Analysis на листе Анализ? Более высокая скорость в активном меню запуска также указывает на это. Чтобы проверить это, сравните время (с включенной строкой .activate и отключенной), когда VBA работает без записи значений (отключите блок с помощью ThisWorkbook.Sheets ("Analysis"). ListObjects ("Analysis_Others"). ListRows .Добавить), поскольку значения на листах (и, следовательно, в графической памяти c) не изменяются все время. Здесь я предполагаю, что лист анализа является активным листом, когда у вас отключена строка .Activate - однако вы упомянули ту же разницу, когда у вас был активен пустой лист, поэтому я не думаю, что он может что-то изменить.

2) Более короткие ссылки на данные. Есть ли какие-либо ссылки, выполняемые через панель инструментов? Как и в формулах или таблицах, которые указывают на другие листы, или в сводную таблицу, получающую данные из листа Dashboard: выборка данных во время VBA через [thisworkbook -> текущий активный лист] может быть быстрее, чем [thisworkbook -> find worksheet - > данные с панели приборов]. Сначала я думал, что ваш сводный стол находится на листе Dashboard, но, читая еще раз, он был на другом. Так что вряд ли.

3) Это не сам лист Dashboard, а текущий индекс листа Dashboard, который вызывает разницу. Я не знаю почему, но я помню, как читал один или два раза, что рабочие книги быстрее, если листы с множеством ячеек с формулами / когда цепочки вычислений находятся в конце рабочей книги (на последних листах рабочей книги). Это указывает на то, что скорость Excel связана с индексами листа, и поэтому разница в скорости связана не с самим листом панели мониторинга, а с тем, что лист панели мониторинга теперь (например) является первым листом рабочей книги. Попробуйте переместить лист панели инструментов к противоположному концу, где он находится сейчас (если это лист (1), переместите его на лист (15)), активируйте лист 1 и снова запустите проверку скорости. Если VBA теперь быстрее с активным другим листом, он все равно не отвечает на ваш вопрос, почему, но, по крайней мере, есть преимущество.

Кроме того, в погоне за более быстрым VBA: Скорее всего, как следует из названия, на листе панели инструментов отображаются данные с вкладки Анализ. Поскольку таблица на вкладке «Анализ» неоднократно обновляется во время VBA, то же самое относится и к ссылкам на эту таблицу (а также к вкладке «Панель инструментов»). Вероятно, быстрее записать анализ сначала в память (в массив), а затем в конце VBA записать его в таблицу: таким образом размер таблицы и все ее ссылки должны изменяться только один раз, а не каждый раз, когда 1 строка добавлена.

0 голосов
/ 01 февраля 2020

Из вашего OP единственное (очевидное) различие между рабочими листами Sheets("Dashboard") и Sheets(15) состоит в том, что первое заполнено некоторыми данными, формулами и т. Д. c.

Без дополнительных подробностей о содержание Dashboard, трудно сказать, в чем причина разницы в скорости, но, безусловно, можно настроить более детальное тестирование, вставив в код больше контрольных точек за истекшее время. Это поможет выявить виновника.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...