В работе разработчика 1С вопросы производительности всегда стоят на первом месте. Однако понятие «скорость» в программировании многогранно: иногда нам нужно ускорить выполнение тяжелого алгоритма, а иногда — намеренно замедлить процесс, например, для ожидания ответа от внешнего сервиса или разделения нагрузки на сервер. В этой статье мы подробно разберем основные методики управления временем выполнения кода, проанализируем классические ошибки и рассмотрим современные подходы к архитектуре высокопроизводительных систем.
Среди разработчиков 1С существует устойчивое мнение, что запрос в цикле — это «смертный грех». С точки зрения классической теории баз данных, это действительно так. Давайте разберем по шагам, что происходит, когда вы выполняете Запрос.Выполнить() внутри цикла Для каждого.
Основная проблема заключается не в самом тексте запроса, а в так называемом Network Roundtrip — сетевых задержках. Каждый вызов запроса инициирует обращение от сервера приложений 1С к серверу СУБД (например, MS SQL Server или PostgreSQL). Даже если сам запрос выполняется за 0,001 секунды, накладные расходы на установку соединения, передачу параметров и получение результата могут составлять десятки миллисекунд. При 1000 итераций цикла программа потратит десятки секунд только на «общение» между серверами.
Однако, как отмечают участники обсуждения, в некоторых случаях профессионалы сознательно идут на это, если объем выборки мал (например, 3-5 итераций) или если разработка сложного пакетного запроса займет несоизмеримо больше времени, чем принесет выгоды. Рассмотрим пример того, как делать не рекомендуется:
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Цена ИЗ РегистрСведений.Цены.СрезПоследних(&Дата, Номенклатура = &Номенклатура)";
Запрос.УстановитьПараметр("Дата", ТекущаяДата());
Запрос.УстановитьПараметр("Номенклатура", СтрокаТЧ.Номенклатура);
// Это замедляет работу из-за постоянных обращений к СУБД
Результат = Запрос.Выполнить();
КонецЦикла;
Правильный подход: выгрузить все необходимые ключи (в данном случае — номенклатуру) в массив или таблицу значений, передать их в один запрос и получить результат целиком. Проанализируем ситуацию: один запрос с условием ГДЕ Номенклатура В (&МассивНоменклатуры) отработает в десятки раз быстрее, чем сотня мелких запросов.
Иногда перед программистом стоит обратная задача — приостановить выполнение кода. Это часто требуется при интеграции с внешними системами (API маркетплейсов, банков), которые имеют лимиты на количество запросов в секунду. Если 1С будет отправлять данные слишком быстро, сервер на той стороне заблокирует IP-адрес компании.
Рассмотрим основные способы реализации паузы в 1С:
ОбщегоНазначенияБТС.Пауза(). Она корректно работает на стороне сервера и часто используется для ожидания завершения фоновых заданий.WScript.Shell. Рассмотрим пример кода:
Процедура ПриостановитьВыполнение(Секунд)
ОбъектWSH = Новый COMОбъект("WScript.Shell");
Команда = "ping -n 1 -w " + Формат(Секунд * 1000, "ЧГ=0") + " 127.255.255.255";
ОбъектWSH.Run(Команда, 0, Истина);
КонецПроцедуры
Важный момент: использование метода Sleep через COM-объекты может полностью блокировать поток выполнения, что в клиентском приложении приведет к «зависанию» интерфейса. Для управляемых форм в современных версиях платформы (8.3.18+) лучше использовать асинхронный метод Ожидать().
Выясним причину, по которой 1С изменила классическую методику контроля остатков. Это один из самых ярких примеров того, как изменение логики «ускорение через архитектуру» работает на практике.
Старая методика (контроль перед записью): Программа сначала ставит блокировку на чтение остатков, проверяет, хватает ли товара, и только потом записывает движения. В многопользовательской среде это создает очереди: пока один пользователь проверяет остатки, остальные ждут. Это существенно замедляет общую работу системы.
Новая методика (контроль после записи): Рассмотрим этот алгоритм подробнее. 1С записывает движения документа сразу, даже если остаток уйдет в «минус». Затем одним запросом система проверяет: «А не стали ли итоги по этому товару отрицательными после моей записи?». Если стали — транзакция откатывается (Rollback). Этот метод значительно быстрее, так как:
Разберем популярный спор о том, влияет ли написание условия Если ... Тогда в одну строку на производительность. С технической стороны, встроенный язык 1С компилируется в байт-код. Для компилятора наличие лишних переносов строк или пробелов не имеет значения — они игнорируются при генерации исполняемого кода.
Однако на что действительно стоит обратить внимание, так это на количество обращений «через точку». Проанализируем код:
// Плохой пример: каждое обращение через точку — скрытый запрос к базе
СкладНаименование = Объект.Склад.Наименование;
ОрганизацияНаименование = Объект.Организация.Наименование;
Каждое такое обращение (если объект не кэширован) заставляет платформу выполнять неявный запрос к таблице справочника. В цикле такие «точки» превращаются в сотни лишних запросов. Правильнее будет получить все нужные данные одним запросом или использовать ПолучитьОбъект() только в крайнем случае.
Как справедливо заметили участники обсуждения, «перевод строки замедляет работу программиста, но облегчает понимание». Всегда нужно искать баланс. Если код выполняется 5 минут, но запускается раз в месяц — возможно, его оптимизация не окупит затрат на разработку. Но если речь идет о проведении чека на кассе или массовом формировании заказов, каждая миллисекунда становится критичной.
Основные выводы нашего анализа: