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