Как ускорить вывод на печать больших табличных документов в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с крупными документами или отчетами в 1С, содержащими более 3000 позиций, разработчики часто сталкиваются с критическим падением производительности. Ситуация, когда макет формируется по 10–15 минут, абсолютно недопустима для бизнес-процессов. Основная сложность заключается в том, что стандартные методы платформы при росте объема данных начинают работать экспоненциально медленнее.

В этой статье мы подробно проанализируем причины замедления графического движка платформы 1С при формировании печатных форм и разберем по шагам практические методы оптимизации, которые позволят сократить время вывода табличного документа в десятки раз.

Выясняем причину: почему стандартный вывод работает медленно?

Прежде чем приступать к написанию кода, давайте проанализируем ситуацию и определим узкие места. Замедление процесса формирования печатной формы обычно складывается из следующих факторов:

  1. Экспоненциальный рост времени работы метода ПроверитьВывод(). Этот метод предназначен для контроля разбиения табличного документа на страницы. Однако при проверке каждой новой строки платформа вынуждена рассчитывать геометрию всего накопленного ранее объема страниц. На 100-й странице проверка одной строки может занимать секунды, превращая вывод 3000 строк в бесконечный процесс.
  2. Обращение к драйверу принтера. Метод ПроверитьВывод() напрямую зависит от настроек операционной системы и активного принтера. При каждом вызове происходит опрос метрик печати, что при сетевом или недоступном принтере вызывает длительные зависания.
  3. Использование свойства АвтоВысотаСтроки. Расчет высоты ячеек под динамический текст требует значительных ресурсов процессора на рендеринг шрифтов для каждой строки.
  4. Неверная архитектура вызовов Клиент-Сервер. Формирование макета в цикле на клиенте с постоянными обращениями к серверу за данными «убивает» производительность из-за сетевых задержек.

Рассмотрим подробнее каждый из путей оптимизации.

Решение 1: Оптимизация проверки вывода методом «двух документов»

Это самый мощный и эффективный способ оптимизации постраничного вывода. На форуме был предложен буферный метод проверки, который позволяет полностью уйти от проблемы замедления ПроверитьВывод(). Разберем его суть подробнее.

Вместо того чтобы выполнять проверку заполнения на основном, постоянно растущем документе, мы будем использовать временный буферный документ, размер которого никогда не превысит одну физическую страницу.

Алгоритм работы метода по шагам:

  1. Создаем два объекта типа ТабличныйДокумент: один итоговый (куда собирается весь результат) и один временный (буферный).
  2. Настраиваем абсолютно идентичные параметры страницы для обоих документов (поля, ориентация, масштаб).
  3. Выводим шапку таблицы и очередную строку во временный буферный документ.
  4. Вызываем ПроверитьВывод() для буферного документа. Так как в буфере находится не более одной страницы, метод отрабатывает мгновенно.
  5. Если строка помещается — продолжаем заполнение буфера.
  6. Если строка не помещается — переносим накопленные в буфере данные в итоговый документ с помощью метода Вывести(), добавляем разделитель страниц, очищаем буфер и заново выводим в него шапку таблицы и текущую строку.

Давайте посмотрим на практический пример реализации этого алгоритма в коде 1С:


// Создаем итоговый и буферный документы
ИтоговыйТабДок = Новый ТабличныйДокумент;
БуферныйТабДок = Новый ТабличныйДокумент;

// Важно установить одинаковые параметры печати, иначе расчет будет неточным
ИтоговыйТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Портрет;
БуферныйТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Портрет;

Макет = ПолучитьМакет("МакетПечатнойФормы");
ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
ОбластьСтрокаТаблицы = Макет.ПолучитьОбласть("СтрокаТаблицы");

// Выводим первоначальную шапку в буфер
БуферныйТабДок.Вывести(ОбластьШапкаТаблицы);

Для Каждого ТекущаяСтрока Из ДанныеДляПечати Цикл
    
    // Заполняем параметры строки
    ЗаполнитьЗначенияСвойств(ОбластьСтрокаТаблицы.Параметры, ТекущаяСтрока);
    
    // Формируем массив проверяемых областей
    МассивОбластей = Новый Массив;
    МассивОбластей.Добавить(ОбластьСтрокаТаблицы);
    
    // Проверяем вывод на буферном документе
    Если Не БуферныйТабДок.ПроверитьВывод(МассивОбластей) Тогда
        
        // Переносим накопленный лист в итоговый документ
        ИтоговыйТабДок.Вывести(БуферныйТабДок);
        ИтоговыйТабДок.ВывестиГоризонтальныйРазделительСтраниц();
        
        // Очищаем буфер и подготавливаем для следующей страницы
        БуферныйТабДок.Очистить();
        БуферныйТабДок.Вывести(ОбластьШапкаТаблицы);
        
    КонецЕсли;
    
    // Добавляем строку в буферный документ
    БуферныйТабДок.Вывести(ОбластьСтрокаТаблицы);
    
КонецЦикла;

// Выводим оставшиеся в буфере строки, если они есть
Если БуферныйТабДок.ВысотаТаблицы > ОбластьШапкаТаблицы.ВысотаТаблицы Тогда
    ИтоговыйТабДок.Вывести(БуферныйТабДок);
КонецЕсли;

Применение этого несложного приема позволяет сократить время генерации отчета на 3000 строк с 15 минут до 15-20 секунд, так как сложность алгоритма проверки падает с экспоненциальной до линейной.

Решение 2: Устранение влияния драйвера принтера

При вызове метода ПроверитьВывод() платформа 1С обращается к графическому контексту принтера, заданного по умолчанию в операционной системе пользователя. Если принтер сетевой и в данный момент недоступен, операционная система уходит в режим ожидания (таймаут), что приводит к длительным зависаниям 1С.

Для предотвращения этой проблемы рекомендуется придерживаться следующих правил:

  1. Использование локального принтера. Установите на компьютерах пользователей виртуальный локальный принтер (например, «Microsoft Print to PDF» или «Microsoft XPS Document Writer») в качестве принтера по умолчанию. Это гарантирует мгновенный ответ операционной системы при запросах метрик страницы.
  2. Очистка параметров печати в коде. Свойство КлючПараметровПечати сохраняет настройки принтера конкретного пользователя. Если сохраненный принтер перестал существовать, это вызовет проблемы. Рекомендуется очищать или переопределять это свойство принудительно перед формированием больших документов:

// Очищаем ключ параметров печати, чтобы избежать привязки к несуществующим принтерам
ТабДок.КлючПараметровПечати = "";

Решение 3: Отказ от автоматической высоты строк (АвтоВысотаСтроки)

Свойство ячеек макета АвтоВысотаСтроки заставляет платформу производить сложный расчет геометрических параметров шрифта и текста для каждой строки таблицы. Если у вас выводятся тысячи строк, это колоссальная нагрузка на процессор.

Как оптимизировать этот процесс:

Установите в макете фиксированную высоту строк. Если в документе присутствуют длинные наименования номенклатуры, которые обязательно должны переноситься, лучше реализовать программный расчет высоты строки на основе длины текста. Это работает значительно быстрее, так как не задействует графический рендеринг операционной системы для каждой ячейки.

Проанализируем пример функции для ручной установки высоты строки:


СреднееКоличествоСимволовВСтроке = 45; // Ширина колонки в символах
БазоваяВысота = 15; // Высота одной строки в пунктах

Для Каждого СтрокаДанных Из ДанныеПечати Цикл
    ЗаполнитьЗначенияСвойств(ОбластьСтрока.Параметры, СтрокаДанных);
    
    ДлинаТекста = СтрДлина(СтрокаДанных.НаименованиеПолное);
    
    Если ДлинаТекста > СреднееКоличествоСимволовВСтроке Тогда
        // Рассчитываем примерное количество строк
        КоличествоСтрок = Цел(ДлинаТекста / СреднееКоличествоСимволовВСтроке) + 1;
        ОбластьСтрока.Область().ВысотаСтроки = КоличествоСтрок * БазоваяВысота;
    Иначе
        ОбластьСтрока.Область().ВысотаСтроки = БазоваяВысота;
    EndIf;
    
    ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;

Такой подход позволяет полностью исключить тяжелые вызовы перерасчета графической сетки платформой.

Решение 4: Архитектурная оптимизация и оптимизация оформления

Важно помнить о распределении ролей между клиентом и сервером. Весь процесс выборки данных, заполнения параметров макета и формирования табличного документа должен происходить исключительно на стороне сервера.

Если вы будете в цикле на клиенте запрашивать данные или макеты с сервера, время формирования увеличится в сотни раз из-за постоянной сериализации и передачи данных по сети. На клиент должен возвращаться уже полностью готовый и сформированный объект ТабличныйДокумент.

Также обратите внимание на оформление табличного документа. Каждый уникальный шрифт, цвет рамки, стиль границы или объединение ячеек увеличивают размер XML-структуры, в которую сериализуется табличный документ при передаче с сервера на клиент. Делайте дизайн больших таблиц максимально простым и лаконичным. Избегайте использования картинок, узоров и сложных градиентов в строках табличной части.

Применяя комплексный подход — буферизацию при проверке вывода, управление параметрами печати, программный расчет высоты строк и строгий серверный вызов — вы гарантированно решите проблему медленной печати больших документов и обеспечите комфортную работу пользователей.

← На главную