Как запустить многопоточное выполнение из внешней обработки без регистрации в базе

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

При разработке инструментов автоматизации на платформе 1С:Предприятие 8.3 часто возникает необходимость ускорить тяжелые операции (обработку больших массивов данных, загрузку файлов или массовое создание документов) с помощью многопоточности. Стандартный механизм БСП (Библиотеки стандартных подсистем) ВыполнитьПроцедуруВНесколькоПотоков отлично справляется с этой задачей для объектов, встроенных в конфигурацию. Однако, если мы запускаем внешнюю обработку просто через меню «Файл — Открыть», возникают сложности: фоновые задания, которые создаются для потоков, «не видят» контекста открытого внешнего файла. Рассмотрим, как обойти это ограничение и правильно настроить многопоточность.

Почему стандартный вызов не работает для внешних файлов

Разберем причину проблемы. Когда мы запускаем процедуру в несколько потоков, система создает новые сеансы (фоновые задания). В этих сеансах нет информации о том, какой файл .epf открыт у пользователя в основном сеансе. Для системы это просто неизвестный объект. Типовой механизм БСП рассчитан на то, что обработка либо зарегистрирована в справочнике ДополнительныеОтчетыИОбработки, либо является частью метаданных. Чтобы запустить код из «неподключенной» обработки, нам нужно явно передать тело этой обработки в фоновое задание.

Шаг 1: Подготовка внешней обработки для передачи в фон

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

Проанализируем программный код инициализации:


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

КонецПроцедуры

Шаг 2: Реализация экспортной процедуры в модуле объекта

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

Рассмотрим структуру метода в модуле объекта:


// Процедура должна принимать параметры, которые мы подготовили в "НаборПараметров"
Процедура ВыполнитьПорциюДанных(ПараметрыПорции, ДополнительныеПараметры) Экспорт
    
    // Здесь реализуем основную логику обработки части данных
    Для Каждого СтрокаДанных Из ПараметрыПорции.ТаблицаДляОбработки Цикл
        // Обработка данных (например, создание документов)
        Попытка
            ОбработатьОбъект(СтрокаДанных);
        Исключение
            ЗаписатьОшибкуВЛог(ОписаниеОшибки());
        КонецПопытки;
    КонецЦикла;
    
КонецПроцедуры

Шаг 3: Решение проблемы дублирования данных (порций)

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

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

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


Функция ПодготовитьПорцииДанных()
    
    НаборПараметров = Новый Соответствие;
    КоличествоПотоков = 4;
    
    Для НомерПотока = 1 По КоличествоПотоков Цикл
        
        ПараметрыПотока = Новый Структура;
        // Обязательно создаем копию таблицы или части массива
        ПараметрыПотока.Вставить("ТаблицаДляОбработки", ИсходнаяТаблица.Скопировать(СтрокиЭтойПорции));
        
        НаборПараметров.Вставить(НомерПотока, ПараметрыПотока);
        
    КонецЦикла;
    
    Возврат НаборПараметров;
    
КонецФункции

Шаг 4: Отладка фоновых заданий внешней обработки

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

Выполним следующие настройки для отладки:

  1. В конфигураторе перейдем в меню «Отладка — Подключение — Автоматическое подключение» и установим флажок «Фоновые задания».
  2. Если база клиент-серверная, убедимся, что сервер запущен с ключом -debug.
  3. Используем метод «остановки» потока. В начале процедуры ВыполнитьПорциюДанных можно добавить код, который зацикливает выполнение до появления определенного файла на диске или записи в журнале регистрации. Это даст вам время вручную подключиться к нужному сеансу через меню подключения.
  4. Самый надежный способ для проверки данных — использование ЗаписьЖурналаРегистрации. Записывайте структуру ПараметрыПорции сразу при входе в процедуру. Если данные дублируются, вы увидите это в журнале без использования отладчика.

Ограничения и рекомендации

Разберем дополнительные факторы, влияющие на успех реализации:

Таким образом, мы выяснили, что запуск многопоточности из внешней обработки возможен даже без её регистрации в системе. Ключевым моментом является передача двоичных данных самого .epf файла через параметры длительных операций и строгий контроль за копированием данных при формировании порций для потоков. Для быстрого старта и практической реализации вы можете использовать готовый шаблон для многопоточной обработки данных на БСП.

← На главную