Как избежать блокировки интерфейса 1С при длительной загрузке данных из Excel

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

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

Почему блокируется интерфейс программы

Выясним причину зависания интерфейса. Когда чтение файла и заполнение данных выполняются в контексте клиентского потока или через прямой синхронный вызов сервера &НаСервере, клиентское приложение переходит в режим ожидания ответа. Пока серверный или клиентский вызов не завершит обработку всех строк, управление пользователю не возвращается.

Попытки скрыть форму или изменить ее видимость программно не приносят результата: платформа все равно ожидает окончания выполнения запущенной процедуры. Кроме того, использование устаревшей технологии COM (объект COMОбъект("Excel.Application")) существенно замедляет процесс, так как инициализирует отдельный процесс операционной системы и работает строго синхронно.

Для решения задачи необходимо перенести тяжелые вычисления в асинхронный фоновый поток на стороне сервера.

Решение 1. Использование подсистемы «Длительные операции» БСП

Если конфигурация разработана на базе Библиотеки стандартных подсистем (например, «1С:Управление торговлей», «1С:ERP», «1С:Комплексная автоматизация» или «1С:Бухгалтерия предприятия»), правильным решением по стандартам разработки 1С является использование подсистемы Длительные операции.

Разберем по шагам алгоритм реализации неблокирующей загрузки через БСП:

  1. Передача файла на сервер: на клиенте помещаем выбранный пользователем файл во временное хранилище.
  2. Запуск фонового задания: вызываем метод ДлительныеОперации.ЗапуститьВыполнениеВФоне, передавая адрес файла во временном хранилище.
  3. Обработка на сервере: экспортная серверная процедура считывает файл, формирует таблицу значений или массив структур с готовыми данными и помещает результат в переданный адрес временного хранилища.
  4. Ожидание на клиенте без блокировки интерфейса: клиентская форма открывает немодальное окно ожидания с помощью ДлительныеОперацииКлиент.ОжидатьЗавершение или периодически проверяет статус задания через таймер, оставляя остальной интерфейс 1С полностью доступным.
  5. Получение результата: после успешного завершения фонового задания форма забирает данные из временного хранилища и заполняет табличную часть документа.

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


&НаКлиенте
Процедура ЗагрузитьИзExcel(Команда)
    
    ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
    ПараметрыДиалога.Заголовок = "Выберите файл Excel для загрузки";
    ПараметрыДиалога.Фильтр = "Файлы Excel (*.xlsx;*.xls)|*.xlsx;*.xls";
    
    ОповещениеЗавершения = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
    НачатьПомещениеФайлаНаСервер(ОповещениеЗавершения, , , ПараметрыДиалога, УникальныйИдентификатор);
    
КонецПроцедуры

&НаКлиенте
Процедура ПослеПомещенияФайла(ОписаниеПомещенногоФайла, ДополнительныеПараметры) Экспорт
    
    Если ОписаниеПомещенногоФайла = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Запускаем длительную операцию на сервере
    ПараметрыПроцедуры = Новый Структура;
    ПараметрыПроцедуры.Вставить("АдресФайла", ОписаниеПомещенногоФайла.Адрес);
    
    ДлительнаяОперация = ЗапуститьФоновуюЗагрузку(ПараметрыПроцедуры);
    
    ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
    ПараметрыОжидания.ТекстСообщения = "Выполняется чтение и обработка файла Excel...";
    ПараметрыОжидания.ВыводитьПрогрессВыполнения = Истина;
    
    ОповещениеОкончания = Новый ОписаниеОповещения("ПослеЗавершенияЗагрузки", ЭтотОбъект);
    ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, ОповещениеОкончания, ПараметрыОжидания);
    
КонецПроцедуры

&НаСервере
Функция ЗапуститьФоновуюЗагрузку(ПараметрыПроцедуры)
    
    ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
    ПараметрыВыполнения.НаименованиеФоновогоЗадания = "Загрузка данных из Excel";
    
    Возврат ДлительныеОперации.ЗапуститьВыполнениеВФоне(
        "ЗагрузкаДанныхСервер.ПрочитатьФайлExcel", 
        ПараметрыПроцедуры, 
        ПараметрыВыполнения
    );
    
КонецФункции

Рассмотрим серверный метод фонового задания в общем модуле ЗагрузкаДанныхСервер:


Процедура ПрочитатьФайлExcel(ПараметрыПроцедуры, АдресРезультата) Экспорт
    
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(ПараметрыПроцедуры.АдресФайла);
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
    ДвоичныеДанные.Записать(ИмяВременногоФайла);
    
    ТабДок = Новый ТабличныйДокумент;
    ТабДок.Прочитать(ИмяВременногоФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
    УдалитьФайлы(ИмяВременногоФайла);
    
    ТаблицаРезультат = Новый ТаблицаЗначений;
    ТаблицаРезультат.Колонки.Добавить("Номенклатура");
    ТаблицаРезультат.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
    ТаблицаРезультат.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));
    
    Для НомерСтроки = 2 По ТабДок.ВысотаТаблицы Цикл
        НоваяСтрока = ТаблицаРезультат.Добавить();
        НоваяСтрока.Номенклатура = ТабДок.Область(НомерСтроки, 1).Текст;
        НоваяСтрока.Количество   = Число(ТабДок.Область(НомерСтроки, 2).Текст);
        НоваяСтрока.Цена         = Число(ТабДок.Область(НомерСтроки, 3).Текст);
    КонецЦикла;
    
    ПоместитьВоВременноеХранилище(ТаблицаРезультат, АдресРезультата);
    
КонецПроцедуры

После получения сигнала об успешном завершении вызывается процедура оповещения, которая заполняет табличную часть:


&НаКлиенте
Процедура ПослеЗавершенияЗагрузки(Результат, ДополнительныеПараметры) Экспорт
    
    Если Результат = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    Если Результат.Статус = "Выполнено" Тогда
        ЗаполнитьТабличнуюЧастьИзХранилища(Результат.АдресРезультата);
        ПоказатьОповещениеПользователя("Загрузка завершена", , "Данные успешно добавлены в документ.");
    ИначеЕсли Результат.Статус = "Ошибка" Тогда
        ВызватьИсключение Результат.ПодробноеПредставлениеОшибки;
    КонецЕсли;
    
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьТабличнуюЧастьИзХранилища(АдресРезультата)
    
    ТаблицаДанных = ПолучитьИзВременногоХранилища(АдресРезультата);
    Если ТипЗнч(ТаблицаДанных) = Тип("ТаблицаЗначений") Тогда
        Объект.Товары.Загрузить(ТаблицаДанных);
    КонецЕсли;
    
КонецПроцедуры

Решение 2. Использование менеджера фоновых заданий платформы

Если конфигурация является самописной или БСП не внедрена, применим прямой механизм платформы через объект ФоновыеЗадания.

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

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

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


&НаСервере
Функция ЗапуститьЗаданиеНапрямую(АдресФайла)
    
    ПараметрыЗадания = Новый Массив;
    ПараметрыЗадания.Добавить(АдресФайла);
    ПараметрыЗадания.Добавить(УникальныйИдентификатор);
    
    Задание = ФоновыеЗадания.Выполнить("ЗагрузкаДанныхСервер.ВыполнитьФоновоеЧтение", ПараметрыЗадания, , "Фоновая загрузка");
    Возврат Задание.УникальныйИдентификатор;
    
КонецФункции

Оптимизация скорости разбора файлов Excel

Для дополнительного ускорения работы и снижения нагрузки на сервер рекомендуется отказаться от использования COM-объектов в пользу более быстрых инструментов:

  1. Объект ТабличныйДокумент: метод ТабличныйДокумент.Прочитать() со способом чтения значений работает быстро, не требует установленного Microsoft Office и одинаково стабильно функционирует как под управлением Windows, так и на серверах Linux.
  2. Прямой разбор через ЧтениеZipФайла и ЧтениеXML: формат .xlsx представляет собой zip-архив с XML-документами. Прямое чтение файлов sharedStrings.xml и листов книги позволяет обрабатывать файлы размером в сотни тысяч строк за считанные секунды.

Важные нюансы и ограничения:

  1. Файловый режим базы: в файловых информационных базах фоновые задания выполняются последовательно в специальном или клиентском сеансе, поэтому запуск задачи может происходить с небольшой задержкой.
  2. Конфликты блокировок: если фоновое задание напрямую перезаписывает документ в базе, а пользователь в этот момент держит документ открытым на редактирование, возникнет конфликт блокировки версий данных. Передавайте результат во временное хранилище формы либо закрывайте форму перед фоновым созданием объекта.
← На главную