В процессе разработки высоконагруженных систем на базе 1С:Предприятие программисты часто сталкиваются с проблемой "тяжелых" внешних компонентов или COM-объектов. Типичный пример — системы распознавания текста (OCR), такие как ABBYY SDK. Инициализация подобного ядра может занимать значительное время (от 30 до 60 секунд), в то время как сама операция обработки файла длится всего несколько секунд. Если каждый из десяти пользователей будет тратить минуту на ожидание при каждом обращении, эффективность работы системы стремится к нулю.
Разберем подробно, почему стандартные механизмы 1С не всегда позволяют решить эту задачу "в лоб", и проанализируем архитектурные подходы, которые помогут инициализировать компоненту один раз и использовать её коллективно.
Прежде всего, проанализируем ситуацию с общими модулями с повторным использованием значений. В 1С такие модули позволяют кэшировать результат функции на время сеанса или на время вызова. Однако здесь есть два критических ограничения:
COMОбъект — это дескриптор в памяти конкретного рабочего процесса rphost. Его нельзя просто так "передать" из одной области памяти в другую.Также рассмотрим объект ПараметрыПриложения. Это полезный механизм для хранения клиентских настроек, но, как справедливо замечено в обсуждении, он недоступен в серверном контексте и не предназначен для хранения "живых" программных интерфейсов внешних библиотек.
Этот метод считается классическим для 1С и не требует стороннего ПО. Мы разделяем процесс на "Заказчиков" (пользователей) и "Исполнителя" (служебный сеанс).
Алгоритм реализации:
РегистрСведений.ОчередьЗадачРаспознавания. Поля: ФайлДанных (ХранилищеЗначения), Статус (Новый, ВРаботе, Завершено), Результат (Строка или Хранилище).
// В служебном сеансе-обработчике
Процедура ИнициализироватьИРаботать()
Попытка
Engine = Новый COMОбъект("ABBYY.PassportReaderSdk.RecognitionEngine");
Исключение
ЗаписатьЛог("Ошибка инициализации SDK");
Возврат;
КонецПопытки;
Пока Истина Цикл
Задача = ПолучитьНовуюЗадачуИзРегистра();
Если Задача = Неопределено Тогда
Приостановить(5); // Пауза 5 секунд, чтобы не грузить CPU
Продолжить;
КонецЕсли;
// Обработка
Результат = Engine.Recognize(Задача.Данные);
СохранитьРезультатВРегистр(Задача.ID, Результат);
КонецЦикла;
КонецПроцедуры
Преимущества: Компонента инициализирована один раз. Все 10 пользователей лишь добавляют записи в регистр и ждут результата. Память сервера расходуется экономно.
Если ваша компонента является COM-объектом, мы можем заставить саму операционную систему управлять её жизненным циклом. Это позволяет вынести объект за пределы жизненного цикла сессии 1С.
Разберем по шагам настройку в Windows:
Теперь, когда первый пользователь вызовет Новый COMОбъект("..."), ОС создаст процесс и инициализирует SDK. Когда пользователь закончит работу, процесс останется "висеть" в памяти. Второй пользователь подключится к уже готовому, прогретому объекту практически мгновенно.
Это наиболее современный и масштабируемый подход. Мы выносим работу с тяжелым SDK в отдельное небольшое приложение (например, на языке Python, C# или Go), которое работает как локальный веб-сервер.
Как это работает:
HTTPСоединение, передавая файл в теле POST-запроса.Проанализируем пример вызова из 1С:
Соединение = Новый HTTPСоединение("localhost", 8080);
Запрос = Новый HTTPЗапрос("/recognize");
Запрос.УстановитьТелоИзДвоичныхДанных(ФайлКартинки);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния = 200 Тогда
РезультатТекст = Ответ.ПолучитьТелоКакСтроку();
КонецЕсли;
Почему это эффективно: Мы полностью уходим от проблем управления памятью внутри 1С. Если SDK "упадет" или возникнет утечка памяти, это не затронет стабильность рабочего процесса rphost. Кроме того, такой сервис может обслуживать запросы параллельно, если SDK поддерживает многопоточность.
Если архитектурно вы ограничены только средствами 1С и решили использовать общий модуль с повторным использованием значений, необходимо предотвратить "засыпание" и очистку кэша. По умолчанию кэш модуля может очищаться через 20 минут неактивности или раньше при нехватке памяти.
Чтобы объект не умирал, можно настроить регламентное задание, которое раз в 5-10 минут будет обращаться к функции этого модуля под каждым активным пользователем (или использовать одно фоновое задание, если используется механизм разделения данных). Однако, помните, что это лишь "костыль", который не решает проблему инициализации для нового пользователя, который только что зашел в систему.
Выбор конкретного метода зависит от ваших технических возможностей:
Важный момент: При использовании любого из методов совместного доступа обязательно учитывайте вопросы лицензирования SDK. Некоторые лицензии ограничивают количество одновременных потоков или привязываются к ID сессии пользователя. Перед внедрением убедитесь, что выбранная архитектура не нарушает условия использования программного продукта.