Обработка "конца строки" при выполнении кода
Для начала нам нужно разобраться, когда количество строк в коде имеет значение.
По информации с партнерского форума при компиляции модуля 1С в байткод перед первой выполняющейся инструкцией в каждой строке исходного кода платформа вставляет дополнительную команду (опкод новой строки), нужную для:
- проверка отладчика (при разрешенной в процессе 1С отладке) - самая тяжелая операция
- на клиенте предотвращается "замерзание" интерфейса
- на сервере отслеживается потеря связи с клиентом и запрос завершения соединения от администратора
- возможно еще каких то задач
Назовем эти действия условно "служебные проверки".
Достоверно известно, что живой байткод с разрешенной отладкой не отличается от байткода для того же кода с запрещенной отладкой. А необходимость перезапускать процесс 1С при переключении разрешения отладки обусловлена подготовкой неких отладочных сервисов в процессе 1С при его инциализации.
Важно запомнить, что самая тяжелая проверка отладчика выполняется независимо от того, подключен ли отладчик к процессу с разрешенной отладкой. Эта проверка не выполняется только когда отладка запрещена. При подключенном же отладчике кроме проверки отладчика еще выполняются дополнительные действия, но обычно относительно легкие.
Выполнение служебных проверок обычно незаметно, т.к. составляет очень небольшой процент от длительности тяжелой команды встроенного языка (например запроса к серверу СУБД).
Однако иногда встречаются участки кода состоящие только из легких команд встроенного языка и выполняющиеся огромное число раз. В таких случаях служебные проверки могут занимать значительный процент времени работы кода и даже бОльшую его часть. Соответственно чем меньше будет строк в таких участках кода, тем ощутимо ниже будет вклад служебных проверок в длительность выполнения.
Так как проверка отладчика является явным лидером по длительности и выполняется только при разрешенной отладке, то рассмотрим способы управления разрешением отладки.
Как запретить отладку клиентского приложения?
При запуске из конфигуратора нужно в параметрах снять флажок "Устанавливать режим разрешения отладки" и запустить приложение кнопкой "1С:Предприятие (CTRL+F5)"
При независимом запуске клиентского приложения нужно открыть параметры. Если параметр "Отладка в текущем сеансе" НЕ равно "Не разрешена", то нужно в параметре "Отладка при перезапуске" установить "Не разрешать", нажать ОК и перезапустить приложение.
Как изменить разрешение отладки на сервере?
Нужно убрать/добавить в строке запуска службы агента сервера 1С параметр "-debug" и выполнить перезапуск службы.
В подсистеме "Инструменты разработчика" это можно сделать в инструменте "Управление службами серверов 1С".
Компания 1С рекомендует запрещать отладку на сервере с продуктивными базами в частности для исключения влияния проверки отладчика на скорость работы программы. В подавляющей части кода выигрыш от ее запрещения будет незаметным и может быть даже проигрыш в некоторых сценариях. Но редкие участки кода, обладающие указанными в первом разделе особенностями, могут действительно сильно замедляться и не только на сервере. Далее мы рассмотрим пример такого кода.
Чтобы понять, что отладка на сервере разрешена, не имея к нему доступа, обычно достаточно в параметрах конфигуратора указать правильный протокол отладки
и запустить из него на отладку управляемое клиентское приложение и в окне "Предметы отладки" увидеть наличие/отсутствие предметов отладки типа "Сервер"
Пример замедления при разрешенной отладке
Возьмем код загрузки данных в память из свежей статьи на этом же сайте
КоличествоСтрок = 100000;
СтрокаДанных = "pyterochka;75779.04;46907.27;21/1/2012";
ВремяНачала=ТекущаяУниверсальнаяДатаВМиллисекундах();
ТаблицаДанных=Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("ИмяМагазина");
ТаблицаДанных.Колонки.Добавить("Дебит");
ТаблицаДанных.Колонки.Добавить("Кредит");
ТаблицаДанных.Колонки.Добавить("ДатаОперации");
ТаблицаДанных.Колонки.Добавить("МесяцОперации");
Для Счетчик = 1 по КоличествоСтрок Цикл
ТекущиеДанныеМассивом=СтрРазделить(СтрокаДанных,";");
НоваяСтрока=ТаблицаДанных.Добавить();
НоваяСтрока.ИмяМагазина=ТекущиеДанныеМассивом[0];
НоваяСтрока.Дебит=Число(ТекущиеДанныеМассивом[1]);
НоваяСтрока.Кредит=Число(ТекущиеДанныеМассивом[2]);
КускиДаты=СтрРазделить(ТекущиеДанныеМассивом[3], "/");
НоваяСтрока.ДатаОперации=Дата(КускиДаты[2], КускиДаты[1], КускиДаты[0]);
НоваяСтрока.МесяцОперации=НачалоМесяца(НоваяСтрока.ДатаОперации);
КонецЦикла;
ВремяОкончания=ТекущаяУниверсальнаяДатаВМиллисекундах();
Сообщить(СтрШаблон("Время чтения данных %1 мсек.",Строка(ВремяОкончания-ВремяНачала)));
Цикл в этом фрагменте удовлетворяет условиям чувствительного к разрешению отладки кода:
- состоит только из легких команд встроенного языка
- выполняется огромное число раз (высокочастотный)
Эти качества легко проверяются обычным замером производительности отладчика - все строки фрагмента занимают ощутимое и сопоставимое время.
Выполним этот код на толстом клиенте (для удобства переключения разрешения отладки). Для этого скачиваем приложенную внешнюю обработку и без установки в ней флажков нажимаем кнопку сначала при разрешенной отладке. Теперь запустим новое клиентское приложение с запрещенной отладкой и повторим эксперимент.
Мои результаты
- при разрешенной отладке 2.3с
- при запрещенной отладке 1.1с
- 2-х кратное ускорение при запрете отладки
А например на таком искусственном тесте получим 6-кратное ускорение:
Массив = Новый Массив;
Для Индекс = 0 По 100000 Цикл
Массив.Добавить(Истина);
КонецЦикла;
Важно понимать, какой процент вносит и сам фрагмент в общую длительность бизнес-операции. Если он не значительный, то такое ускорение будет незаметным на общем фоне и не стоит внимания.
Применяем однострочный код
Ради ускорения этих редких фрагментов кода для всей конфигурации запрещать отладку не хочется. Тут нам поможет однострочная запись кода. Ведь как мы помним из первого раздела, количество символов "КонецСтроки" играет большое значение. Но если просто взять и преобразовать какой то фрагмент кода в однострочный вид, то будут неудобства
- код потеряет читаемость
- нельзя будет ставить точки останова и делать пошаговую отладку внутри
- замер производительности будет показаться только целиком для всей строки
- когда он выполняется на клиенте, будет "замерзать" интерфейс и не будет работать ОбработкаПрерыванияПользователя()
- когда он выполняется на сервере, не будет отслеживаться потеря связи с клиентом и запрос завершения соединения от администратора
- в стеке описания ошибки такая строка будет включаться целиком и будет непонятно какой именно метод из нее вызван, но обычно в таком коде нет вызовов прикладных методов и потому она очень редко попадает в стек ошибки
- и ряд других неудобств
Чтобы при необходимости оперативно временно устранять эти неудобства, воспользуемся консолью кода из подсистемы "Инструменты разработчика". Вставим в нее код цикла из примера выше и выполним команду "Рефакторинг"/"В однострочный".
Вот какой код она выдала
_РежимОтладки = Ложь;
Если _РежимОтладки Тогда // Можно менять на Истина в точке останова, например условием ирОбщий.ПрЛкс(_РежимОтладки, 1, 1)
// Пассивный оригинал расположенного ниже однострочного кода. Выполняйте изменения синхронно в обоих вариантах.
Для Счетчик = 1 по КоличествоСтрок Цикл
ТекущиеДанныеМассивом=СтрРазделить(СтрокаДанных,";");
НоваяСтрока=ТаблицаДанных.Добавить();
НоваяСтрока.ИмяМагазина=ТекущиеДанныеМассивом[0];
НоваяСтрока.Дебит=Число(ТекущиеДанныеМассивом[1]);
НоваяСтрока.Кредит=Число(ТекущиеДанныеМассивом[2]);
КускиДаты=СтрРазделить(ТекущиеДанныеМассивом[3], "/");
НоваяСтрока.ДатаОперации=Дата(КускиДаты[2], КускиДаты[1], КускиДаты[0]);
НоваяСтрока.МесяцОперации=НачалоМесяца(НоваяСтрока.ДатаОперации);
КонецЦикла;
Иначе
// Однострочный код использован для ускорения при разрешенной отладке. Выше расположен оригинал. Выполняйте изменения синхронно в обоих вариантах. Преобразовано консолью кода из подсистемы "Инструменты разработчика"
Для Счетчик = 1 по КоличествоСтрок Цикл ТекущиеДанныеМассивом=СтрРазделить(СтрокаДанных,";"); НоваяСтрока=ТаблицаДанных.Добавить(); НоваяСтрока.ИмяМагазина=ТекущиеДанныеМассивом[0]; НоваяСтрока.Дебит=Число(ТекущиеДанныеМассивом[1]); НоваяСтрока.Кредит=Число(ТекущиеДанныеМассивом[2]); КускиДаты=СтрРазделить(ТекущиеДанныеМассивом[3], "/"); НоваяСтрока.ДатаОперации=Дата(КускиДаты[2], КускиДаты[1], КускиДаты[0]); НоваяСтрока.МесяцОперации=НачалоМесяца(НоваяСтрока.ДатаОперации); КонецЦикла;
КонецЕсли;
Он состоит из 2-х синхронно изменяемых вариантов кода
- Многострочный код (Пассивный оригинал) - оригинальный код, в обычном режиме он не будет выполняться
- Однострочный код - в обычном режиме выполняется он
Синхронное изменение обеспечивается ручным обновлением однострочного варианта кода рассмотренной выше командой консоли кода после изменения пассивного оригинала.
Так мы устранили в постоянном режиме потерю читаемости кода путем добавления небольшого риска несогласованности (можно забыть обновить однострочный вариант кода).
Переключение между однострочным и многострочным вариантами
Выбор варианта исполнения кода делается изменением булевой переменной _РежимОтладки. Ее можно менять
- в точке останова вручную
- в условной точке останова автоматически, например при подключенном расширении "Инструменты разработчика" условием "ирОбщий.ПрЛкс(_РежимОтладки, 1, 1)"
- глобально, если присваивать ей везде какой то глобальный флаг
Таким образом мы в рамках конкретного сеанса можем управлять выбором выполнения варианта этого кода.
Вернемся к нашей внешней обработке с примером. Туда уже вставлен наш новый код и флаг выбора варианта связан с флажком "Однострочный код" на форме.
Повторяем выполнение примера в режиме однострочного кода
Устанавливаем на форме флажок "Однострочный код" и повторяем тест с разрешенной отладкой и с запрещенной. Мои результаты
- при разрешенной отладке 1.1с
- при запрещенной отладке 1.1с
- длительность не изменилась
Вывод
В проведенных тестах мы убедились, что независимо от разрешения отладки однострочный код дает ту же скорость, что многострочный дает при запрещенной отладке. Таким образом нейтрализуется негативное влияние разрешенной отладки на работу легкого высокочастотного кода.