Хронометраж
Давайте воспользуемся последним макросом, чтобы посмотреть на временной профиль выполнения тех или иных операций. Мне кажется, достаточно интересно, а иногда и крайне важно понять, на что уходит основное время при выполнении того или иного макроса. Я хотел понять также, как меняются временные затраты, если изменить реализацию макроса. Кроме того, нелишне напомнить Вам о необходимости следить за эффективностью выполнения программы.
Для того, чтобы построить временной профиль, я использую функцию Timer, добавляю специальные переменные для хранения времени выполнения отдельных участков процедуры и вставляю операторы, следящие за временем выполнения. Вот как выглядит теперь текст вышеприведенного макроса с надстройками, позволяющими проводить хронометраж операций:
Листинг 2.23.
(html, txt)
Приведу данные хронометража результатов испытания работы этой процедуры на одном из текстов.
TAll - Общее время работы | 2,187 | 1,96 | 1,95 |
TForEach - Время работы внешнего цикла для конструкции For Each | 2,078 | 1,86 | 1,86 |
TSelect - Время работы конструкции Select -Case | 1,01 | 0,80 | 1,08 |
TIndex1 - Время1 работы функции Asc | 0 | 0,008 | 0,007 |
TIndex2 - Время2 работы функции Asc | 0 | 0 | 0 |
TSym1 - Время1 работы функции Mid | 0,0078 | 0,031 | 0,04 |
TSym2 - Время2 работы функции Mid | 0 | 0 | 0 |
Поговорим о полученных результатах. Прежде всего, обратите внимание на разброс значений от эксперимента к эксперименту. Этот разброс всегда следует иметь в виду, хотя он, конечно, не искажает качественной картины построения временного профиля. Данные в таблице 1 приведены для случая, когда в макросе используется конструкция For Each для получения очередного символа коллекции Characters и конструкция Select - Case для разбора случаев и анализа того, каким является очередной символ. Вот некоторые выводы, которые можно сделать, анализируя полученные результаты:
- Основное время работы данной процедуры, примерно 2 секунды, затрачивается на организацию цикла (конструкцию For Each) и организацию разбора случаев (конструкцию Select - Case).
- На организацию цикла и разбор случаев тратится примерно равное время, чуть более секунды на организацию цикла и чуть менее секунды на организацию разбора случаев.
- Внутренние операторы конструкции Case, связанные с выполнением встроенных функций Asc и Mid, занимают пренебрежимо малое время в сравнение со временем, требуемым для организации конструкций цикла и разбора случаев, не более 5% от времени работы конструкции Select.
Заменим теперь конструкцию:
Select Case Sym Case "А" To "Я" <операторы1> Case "а" To "я" <операторы2> End Select на конструкцию: If Sym >= "А" And Sym <= "Я" Then <операторы1> ElseIf Sym >= "а" And Sym <= "я" Then <операторы1> End If
Листинг 2.24.
(html, txt)
Результаты вычислений в этом случае показаны в следующей таблице:
TAll - Общее время работы | 2,06 | 2,02 | 1,98 |
TForEach - Время работы внешнего цикла для конструкции For Each | 1,97 | 1,93 | 1,89 |
TSelect - Время работы конструкции If-Then-Else | 0,97 | 0,96 | 0,89 |
TIndex1 - Время1 работы функции Asc | 0,015 | 0,02 | 0,007 |
TIndex2 - Время2 работы функции Asc | 0 | 0 | 0 |
TSym1 - Время1 работы функции Mid | 0,046 | 0,051 | 0,02 |
TSym2 - Время2 работы функции Mid | 0 | 0 | 0 |
Приведем теперь более впечатляющие результаты, заменив конструкцию цикла:
Листинг 2.25.
(html, txt)
на обычный цикл:
For i = 1 To Selection.Characters.Count Sym1 = Selection.Characters(i)
Листинг 2.26.
(html, txt)
Вот как выглядят результаты временных замеров в этом случае:
TAll - Общее время работы | 106,53 | 113,37 | 115,84 |
TForEach - Время работы внешнего цикла для конструкции For Each | 106,44 | 113,27 | 115,74 |
TSelect - Время работы конструкции Select -Case | 0,140 | 0,148 | 0,187 |
TIndex1 - Время1 работы функции Asc | 0,02 | 0,03 | 0,015 |
TIndex2 - Время2 работы функции Asc | 0 | 0 | 0 |
TSym1 - Время1 работы функции Mid | 0,078 | 0,015 | 0,054 |
TSym2 - Время2 работы функции Mid | 0 | 0 | 0 |