Эффект обновления экрана
Я играю вокруг измерения времени выполнения кода, чтобы оценить различия между выполнением моих скриптов локально и на моем сервере. В какой-то момент я забыл отключить screen updating
и был благодарен, что я не чувствителен к проблесковым огням, прежде чем думать об этом более подробно:
Когда я впервые начал использовать VBA
, я всегда предполагал, что он был просто использован, чтобы он не пугал конечных пользователей, думая, что их компьютер вот-вот рухнет. Когда я начал читать больше о повышении эффективности вашего кода, я понял, для чего он нужен, но насколько эффект действительно имеет screen updating
на время выполнения ваших кодов?
Ответы
Ответ 1
Отключение обновления экрана будет иметь значение только для времени выполнения, если код взаимодействует с Excel таким образом, что вызывает изменения содержимого экрана. Чем больше количество изменений экрана, тем больше будет влияние. Другие опубликованные ответы удачно демонстрируют это.
Другими настройками приложения, которые могут повлиять на время выполнения, являются Расчет и Обработка событий. Используйте этот шаблон кода в качестве отправной точки (обработчик ошибок гарантирует, что эти свойства будут снова включены в конце подпрограммы, даже если она содержит ошибки)
Sub YourSub()
On Error GoTo EH
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
' Code here
CleanUp:
On Error Resume Next
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Exit Sub
EH:
' Do error handling
Resume CleanUp
End Sub
Существуют и другие методы, которые могут обеспечить еще большее повышение скорости выполнения.
Самые полезные включают в себя
- Избегайте
Select
, Activate
и ActiveCell/Sheet/Workbook
в максимально возможной степени. Вместо этого объявляйте и назначайте переменные и ссылайтесь на них.
- При ссылке на большие диапазоны скопируйте данные диапазона в массив вариантов для обработки и скопируйте результат обратно в диапазон после.
- Используйте
Range.SpecialCells
, Range.Find
и Range.AutoFilter
, чтобы ограничить количество ячеек, на которые есть ссылки.
Есть много примеров этих методов на SO.
Ответ 2
Если вы хотите увидеть довольно резкий пример того, почему важно ScreenUpdating
, запустите следующий код. В Excel 2011 требуется примерно 45 раз дольше, чтобы запустить этот обмен без ScreenUpdating = false
! Это огромная разница во времени.
Sub testScreenUpdating()
Dim i As Integer
Dim numbSwitches As Integer
Dim results As String
'swap between sheets this number of times
numbSwitches = 1000
'keep track of time
Dim startTime As Double
startTime = Time
'swap between sheets 1/2 (need both sheets or this will crash)
For i = 1 To numbSwitches
Sheets(1 + (i Mod 2)).Select
Next i
'get results
results = "Screen Updating not disabled: " & Format(Time - startTime, "hh:mm:ss") & " seconds"
startTime = Time
'scenario 2 - screenupdating disabled
Application.ScreenUpdating = False
'swap between sheets 1/2 (need both sheets or this will crash)
For i = 1 To numbSwitches
Sheets(1 + (i Mod 2)).Select
Next i
Application.ScreenUpdating = True
'get results for part two
results = results & vbCrLf & "Screen Updating IS disabled: " & Format(Time - startTime, "hh:mm:ss") & " seconds"
'show results
MsgBox results
End Sub
Кроме того, хотя мы говорим о способах повышения эффективности, еще один важный момент заключается в том, что Select
, Selection
и Activate
редко (если когда-либо) необходимы. Когда вы записываете макросы, он всегда будет использовать их, но очень мало ситуаций, когда вам нужно фактически использовать их в коде. Аналогично, что-либо с Active
в заголовке (например, ActiveCell
) обычно является признаком того, что у вас будет более медленный код, потому что вы предположительно выбираете ячейки.
Вы почти всегда можете ссылаться на ячейки/таблицы и избегать выбора. Например:
msgbox (Worksheets(1).Range("A1").value)
будет работать независимо от того, находитесь ли вы на первом листе. Общей новой ошибкой VBA является нечто большее:
Worksheets(1).Select
msgbox (Range("A1").value)
который является ненужным шагом.
Это добавляет значительного времени на время выполнения кода.
Ответ 3
Во-первых, я использовал script, написанный Richie (UK) Post # 7 Здесь
Он просто выполняет итерацию через цикл, изменяя значение я в одной ячейке. Я немного изменил его, чтобы он запустил 10 000 раз, и я выполнил его 10 раз для размера выборки.
Каков эффект обновления экрана при скорости выполнения моих кодов?
Это длительность выполнения, когда Screen Updating
отключен и включен:
Disabled Enabled
0.61909653 2.105066913
0.619555829 2.106865363
0.620805767 2.106866315
0.625528325 2.102403315
0.625319976 2.0991179
0.621287448 2.105103142
0.621540236 2.101392665
0.624537531 2.106866716
0.620401789 2.109004449
Как вы можете видеть, для выполнения кода требуется почти в 3,5 раза больше, если Screen Updating
не отключен.
Оба этих кода были исключены с помощью кнопки "Пуск" в редакторе VB, в отличие от "просмотра" электронной таблицы.
2 простых строки в начале и конце кода:
Application.ScreenUpdating = False
Application.ScreenUpdating = True
Но они могут существенно повлиять на эффективность вашего исполнения!
Примечание. Очевидно, что преимущества Screen Updating
будут хорошо известны многим, но это может принести пользу новичкам, и мне интересно посмотреть номера!
Ответ 4
Существует одна важная информация о обновлении экрана, которую я не видел в предыдущем ответе. Из моего собственного теста я выясняю, что обновление экрана с включенным и включенным окнами занимает около 15 мс (проверено на С# через Excel Interop). Имейте это в виду, если вы будете выполнять все, что займет меньше времени. И в конце концов не включите/выключить обновление экрана много раз в каком-то цикле. Это будет настоящий убийца производительности.
И еще одно примечание (которое вы, вероятно, не хотите слышать), если вы хотите быстро использовать С++. Это обычно в 5-10 раз быстрее (не поймите меня здесь, это зависит от того, что вы действительно делаете), чем VBA.
Ответ 5
Я знаю это старая ветка, но:
- Установите
ScreenUpdating = true
, но не забудьте вернуть его к старому значению.
- Изменение рабочих книг также приводит к сбросу
ScreenUpdating
.