Для тех, кто торопится
Итак, для тех, кому некогда читать эту замечательную статью, сразу даю результат исследования. И так, синтаксическая конструкция «Попытка - Исключение» не оказывает хоть сколь-нибудь заметного влияния на скорость выполнения вашего кода, в случае, когда все работает штатно и исключение не было вызвано.
Для тех, кому интересны подробности
Как работает «Попытка - Исключение» в платформе
Чтобы разобраться с механизмом обработки исключений, нам придется заглянуть под капот нашей любимой платформы. Вся следующая информация взята из фундаментальных работ Андрея Овсянкина про устройство интерпретатора платформы:
База
В моей статье описывается эксперимент, когда прикладной код находится в конструкции «Попытка - Исключение», однако в процессе выполнения этого кода или в событиях самой платформы никаких ошибок не произошло. Иными словами, все отработало без ошибок.
Рассмотрим следующий пример:
Процедура ГенераторНоменклатуры(КоличествоЭлемнтов) Экспорт
Для индекс = 1 По КоличествоЭлемнтов Цикл
Попытка
// Тело блока «Попытка»
НоваяНоменклатура(индекс);
Исключение
// Обработчик исключения
ВызватьИсключение "Ошибка исполнения";
КонецПопытки;
КонецЦикла;
КонецПроцедуры
При компиляции этого метода в байт-код произойдёт следующая трансформация:
Ключевое слово Попытка будет скомпилировано в опкод (операционный код)
BeginTry <адрес начала блока обработчика исключения>
Тело блока «Попытка» будет скомпилировано штатным образом. То, что наш прикладной код находится внутри попытки, на компиляцию не повлияет.
В конце блока кода, помещенного в Попытку, будут добавлены следующие опкоды:
BlckEnd 1
Jmp <адрес первой инструкции за пределами блока обработчика ошибки>
BlckEnd
это какой-то специализированный оператор очистки конца блока. Jmp
это оператор безусловного перехода.
Блок Исключение завершается оператором.
EndTry
Таким образом при исполнении нашего прикладного кода, помещенного в попытку, дополнительно платформой будет выполнено:
- Опкод
BeginTry
, который поместит на стек адрес начала обработчика исключения, иными словами адрес начала блока «Исключение – КонецПопытки» - После успешного выполнения нашего прикладного кода будет выполнен опкод
BlckEnd
, который выполнит некую очистку, наверное, будет очищен блок «Исключение - КонецПопытки», но я до конца не уверен. Также я ожидаю, что этот опкод снимет со стека теперь уже ненужный адрес начала обработчика исключений. - Далее будет выполнен принудительный переход за пределы блока «Исключение - КонецПопытки»
В общем-то и все. Если прикладной код выполнился без ошибки, то разница между кодом, который помещен в блок «Попытка – Исключение», и кодом, который не помещен в обработчик ошибок, заключается в этих трех дополнительных шагах платформы.
Я пристал к коллегам в Телеграм чате https://t.me/oscript_library и на мой вопрос: «Что происходит с кодом, который помещен в обработчик ошибок», Андрей Овсянкин ответил:
Ничего не происходит. Можно посмотреть исходники 1Скрипта, не думаю, что в оригинальной 1С сильно отличается. При слове "Попытка" фиксируется адрес "обработчика" - начало блока Исключение. Если происходит исключение (например, поделили на ноль, вышли за границу массива или бог знает что еще), то исключение ловится, оборачивается в ИнформацияОбОшибке и управление переходит в "обработчик". Изучать то, что происходит в скриптовом движке при исключениях, не имеет смысла. Т. к. он написан на языке, уже имеющем исключения, как концепт. Исключения влияют на что-то только если сравнивать на более низких уровнях, как блок try-catch выглядит на уровне чистого Си или АСМ.
Проверка практикой
Несмотря на крепкую теорию, я все равно решил проверить ее на практике. Давайте нагрузим нашу платформу и выясним, какое влияние оказывает конструкция «Попытка – Исключение» на скорость выполнения кода. Для проверки была подготовлена тестовая конфигурация с различными вариантами проверки.
Тестовый стенд
Характеристики тестового стенда были следующие:
- Платформа: 8.3.24.1439
- Конфигурация: «Демонстрационная информационная база» с добавленными тестовыми сценариями.
- База: файловая и клиент-сервер MS SQL
Тестовые сценарии
Все тестовые сценарии были выполнены по 10 раз на файловой и на клиент-серверной базе.
Тестовый сценарий "Прикладной код работает с памятью"
Сценарий, работающий с памятью, создает упорядоченный массив из трех тысяч чисел, а затем сортирует его пузырьком в обратном порядке.
Первый тест – сценарий выполняется без обработки исключения, то есть конструкция «Попытка - Исключение» отсутствует.
Второй тест – весь сценарий помещен в одну конструкцию «Попытка – Исключение». Таким образом одна попытка на обработку всех 3000 элементов массива.
Третий тест – каждая итерация перестановки при сортировке пузырьком помещена в конструкцию «Попытка – Исключение». Таким образом попытка была на каждый элемент массива.
Результат теста:
Файловая база.
Тест 1, сек. | Тест 2, сек. | Тест 3, сек. |
18,6813 | 18,1613 | 19,368 |
Клиент-серверная база.
Тест 1, сек. | Тест 2, сек. | Тест 3, сек. |
19,846 | 18,7074 | 20,4655 |
Тестовый сценарий "Прикладной код работает с базой"
Сценарий, работающий с базой, создавал и записывал в базу пять тысяч элементов справочника Номенклатура. Сценарий выполнялся в транзакции. После завершения сценария транзакция откатывалась, чтобы забивать базу данными.
Первый тест – сценарий выполняется без обработки исключения, то есть конструкция «Попытка - Исключение» отсутствует.
Второй тест – весь сценарий помещен в одну конструкцию «Попытка – Исключение». Таким образом одна попытка на создание всех 5000 записей справочника.
Третий тест – запись каждого элемента справочника помещена в свою конструкцию «Попытка – Исключение». Таким образом, попытка была на каждый записываемый элемент справочника.
Результат теста:
Файловая база.
Тест 1, сек. | Тест 2, сек. | Тест 3, сек. |
14,0597 | 14,197 | 14,1784 |
Клиент-серверная база.
Тест 1, сек. | Тест 2, сек. | Тест 3, сек. |
18,6108 | 18,4252 | 18,418 |
Выводы
Во всех хороших статьях есть выводы. Моя статья хорошая.
Итак, заключение прикладного кода в конструкцию Попытка – Исключение не оказывает влияния на производительность платформы, если в процессе выполнения не произошло ошибок. Если вы, как и я, опасались лишний раз использовать попытку в своем коде, можете расслабиться, медленнее ваш код работать не станет.
Бонус
И в завершении статьи хотел напомнить о рекомендациях компании 1С. Я уверен, что все это у вас и так как от зубов отскакивает, но вдруг кто-то подзабыл. Итак, на ИТС есть следующие руководства по использованию конструкции Попытка – Исключение:
Перехват исключений в коде. Стандарты разработки.
Обработка исключений. Методическая поддержка.
Руководство разработчика. Платформа 1С:Предприятие 8.3.25. Глава 4.
Также хочу напомнить, что начиная с версии платформы 8.3.21 у нас появилась возможность вызывать исключения не только как оператор, но и как функцию с параметрами. Например, теперь нам доступна вот такая красота:
ВызватьИсключение ("Документ не может быть проведен", КатегорияОшибки.ОшибкаКонфигурации,
"ERR.DOCS.0001", "Клиенту запрещена отгрузка");
Теперь при обработке исключения нам доступны все параметры, которые были указаны при вызове исключения. Чувствуете, все как в "серьезных" языках программирования? Но, если честно, это очень крутая фишка платформы.
Всем спасибо за внимание.
Если статья вам понравилась, буду рад вашему плюсику.
И да, вы можете использовать эту статью как вам угодно, при условии указания автора статьи.