Ускорение чтения правил обмена в УПП 1.3 в 20 раз!

06 октября 2015

Предисловие

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

Сегодня в статье пойдет речь как-раз о решении подобной проблемы. Мы оптимизируем чтение правил обмена на примере конфигурации "Управление производственным предприятием"  (УПП) редакции 1.3. Из названия статьи уже можно понять на сколько значительным!

Суть проблемы

Две конфигурации УПП, объемные правила конвертации, односторонний обмен между центральной и периферийной базой, и периодичность обмена раз в 5 минут - это все что нам дано в этой задаче. Ах да, спросите для чего нужно так часто выполнять обмен? Причин может быть много: нужно оперативно смотреть информацию в центральной базе, нужно выполнять оперативный контроль работы и много другое. Для нас это и не важно сейчас. Есть задача сделать такой обмен - так давайте сделаем!

Размер файла XML правил обмена занимает порядка 120 мегабайт. Когда из периферийной базы запускается процедура выгрузки данных, то на этап "Чтение правил конвертации" тратится порядка 5 минут. По условиям задачи обмен должен выполнятся каждые 5 минут, а не чтение правил! Значит придется решить эту проблему. Сначала проанализируем как сейчас выполняется чтение правил обмена.

В конфигурации есть обработка "ОбменДаннымиXML" которая выполняет все основные функции по выгрузке, загрузке, чтению правил обмена и т.д. В модуле объекта обработки за чтение правил обмена отвечает процедура "ЗагрузитьПравилаОбмена":

// Осуществляет загрузку правил обмена в соответствии с форматом
//
// Параметры:
//  Источник       - Объект, из которого осуществляется загрузка правил обмена;
//  ТипИсточника   - Строка, указывающая тип источника: "XMLФайл", "ЧтениеXML", "Строка"
// 
Процедура ЗагрузитьПравилаОбмена(Источник="", ТипИсточника="XMLФайл", СтрокаСообщенияОбОшибке = "", 
	ЗагружатьТолькоЗаголовокПравил = Ложь) Экспорт

	#Если Клиент Тогда
	Состояние("Выполняется загрузка правил обмена ...");
	#КонецЕсли

В этой процедуре читается XML-файл правил и заполняются служебные переменные, такие как:

  • реквизит обработки "ТаблицаПравилКонвертации", в которой сохраняются все правила конвертации для дальнейшего использования. Большая часть времени при чтении правил затрачивается именно на заполнение этой таблицы.
  • глобальная переменная "Конвертация", в которой сохраняется структура свойств конвертации (имя, ID, обработчики событий и др.)
  • глобальная переменные "Менеджеры" и "МенеджерыДляПлановОбмена", которые хранят соответствие, содержащее поля Имя, ИмяТипа, ТипСсылкиСтрокой, Менеджер, ОбъектМД, ПКО.
  • переменная обработки "Правила", в которой сохраняются ссылки на ПКО.
  • и много другое.

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

Пока ПравилаОбмена.Прочитать() Цикл
	
	ИмяУзла = ПравилаОбмена.ЛокальноеИмя;
       		
	// Реквизиты конвертации
	Если ИмяУзла = "ВерсияФормата" Тогда
		// ...
		
	// События конвертации
		
	ИначеЕсли ИмяУзла = "" Тогда
	
	ИначеЕсли ИмяУзла = "ПослеЗагрузкиПравилОбмена" Тогда
		// ..
		
	// Правила
		
	ИначеЕсли ИмяУзла = "ПравилаВыгрузкиДанных" Тогда
		// ...
		
	// Алгоритмы / Запросы / Обработки
		
	ИначеЕсли ИмяУзла = "Алгоритмы" Тогда
		// ...

	// Выход
	ИначеЕсли (ИмяУзла = "ПравилаОбмена") 
		И (ПравилаОбмена.ТипУзла = одТипУзлаXML_КонецЭлемента) Тогда
		// ...
		
КонецЦикла;

Для более подробной информации Вы можете посмотреть содержимое модуля обработки "ОбменДаннымиXML" в составе конфигурации.

И так при каждом запуске обмена правила выполняются одни и те же действия по чтению правил и инициализации служебных переменных обработки. Что-то тут не так, не правда ли? Зачем выполнять это действие каждый раз, ведь правила конвертации остаются прежними? Нет, в теории конечно правила можно менять каждые 5 минут, то мы такую ситуацию не будем рассматривать =).

И так, вот то самое место, которое требует оптимизации!

Решение

Решение не простое, а очень простое! Мы сохраним КЭШ инициализированных переменных обработки при первом чтении правил конвертации! При последующих чтениях нужно будет лишь восстановить их сохраненных в КЭШе значений настройки обработки, тем самым сэкономив значительную часть времени на этапе чтения правил конвертации.

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

Регистр с настройками хранения КЭШа правил конвертации

Таблица регистр содержит:

  1. Узел - ссылка на любой узел планов обмена
  2. Выгрузка - булев флаг, с помощью которого можно настраивать, когда использовать КЭШ - для выгрузки или для загрузки сообщений
  3. ИспользоватьКэш - булев флаг, с помощью которого можно в любой момент включить или отключить кэширование правил конвертации для выбранного узла
  4. Настройка кэширования правил конвертацииЗначениеКэша - ресурс с типом "ХранилищеЗначений", в котором непосредственно сохраняются инициализированные настройки правил конвертации.

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

В модуле менеджера регистра необходимо добавить следующие процедуры и функции:

// Получает КЭШ правил конвертации для переданного узла
// с учетом флага "Выгрузка"
//
Функция ПолучитьКэш(Узел, Выгрузка) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ЗначениеКэша", Неопределено);
	Результат.Вставить("ИспользоватьКэш", Ложь);
	
	Набор = РегистрыСведений.yy_НастройкиКэшированияПравил.СоздатьНаборЗаписей();
	Набор.Отбор.Узел.Установить(Узел);
	Набор.Отбор.Выгрузка.Установить(Выгрузка);
	Набор.Прочитать();
	Если НЕ Набор.Количество() = 0 Тогда
		Запись = Набор.Получить(0);
		Результат.ИспользоватьКэш = Запись.ИспользоватьКэш;
		Если Запись.ИспользоватьКэш Тогда
			ЗначениеКэша = Запись.ЗначениеКэша.Получить();
			Если ЗначениеКэша = Неопределено Тогда
				Результат.ЗначениеКэша = Неопределено;
			Иначе
				Результат.ЗначениеКэша = ПоместитьВоВременноеХранилище(ЗначениеКэша, Новый УникальныйИдентификатор);
			КонецЕсли;			
		КонецЕсли; 
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции
// Сохраняет КЭШ правил конвертации для переданного узла
// с учетом флага "Выгрузка". В качестве параметра "ЗначениеКэша"
// передается заполненная по данным обработки "ОбменДаннымиXML"
// структура, шаблон которой создается функцией 
//	"ПолучитьПравилаОбменаДляСохраненияВКэш"
//	модуля объекта обработки "ОбменДаннымиXML"
//
Процедура УстановитьКэш(Узел, Выгрузка, ЗначениеКэша) Экспорт
	
	Набор = РегистрыСведений.yy_НастройкиКэшированияПравил.СоздатьНаборЗаписей();
	Набор.Отбор.Узел.Установить(Узел);
	Набор.Отбор.Выгрузка.Установить(Выгрузка);
	Набор.Прочитать();
	Если Набор.Количество() = 0 Тогда
		Запись = Набор.Добавить();
		Запись.Узел = Узел;
		Запись.Выгрузка = Выгрузка;
	Иначе
		Запись = Набор.Получить(0); 
	КонецЕсли;
	
	Если Запись.ИспользоватьКэш Тогда
		Запись.ЗначениеКэша = Новый ХранилищеЗначения(ЗначениеКэша);
		Набор.Записать();
	КонецЕсли;
		
КонецПроцедуры
// Инициализация структуры сохранения в КЭШ настроек обработки
// "ОбменДаннымиXML"
//
Функция ПолучитьСтруктуруСохраненияДанных() Экспорт
		
	СписокПолейТекст =
	"Алгоритмы
	|АрхивироватьФайл
	|АутентификацияWindowsИнформационнойБазыДляПодключения
	|ВерсияПлатформыИнформационнойБазыДляПодключения
	|ВерсияПравилОбмена
	|ВестиДополнительныйКонтрольЗаписиВXML
	|ВыводВОкноСообщенийИнформационныхСообщений
	|ВыводВПротоколИнформационныхСообщений
	|ВыводВПротоколСообщенийОбОшибках
	|ВыгружатьТолькоРазрешенные
	|ВыполнитьОтложенноеПроведениеДокументовПослеЗагрузкиДанных
	|Данные
	|ДатаВыгрузкиДанных
	|ДобавлениеОбъектовИзФоновогоОбмена
	|ДобавлениеОбъектовИзФоновогоОбменаЗагрузка
	|ДопОбработки
	|ДописыватьДанныеВПротоколОбмена
	|ЗагруженныеГлобальныеОбъекты
	|ЗагруженныеОбъекты
	|ЗадаватьВопросПриЗагрузкеДанныхПриОткрытииОбработки
	|ЗаписыватьВИнформационнуюБазуТолькоИзмененныеОбъекты
	|ЗапоминатьЗагруженныеОбъекты
	|Запросы
	|ЗначениеПустаяДата
	|ИмяИнформационнойБазыНаСервереДляПодключения
	|ИмяСервераИнформационнойБазыДляПодключения
	|ИмяФайлаВнешнейОбработкиОбработчиковСобытий
	|ИмяФайлаОбмена
	|ИмяФайлаПравилОбмена
	|ИмяФайлаПротоколаОбмена
	|ИспользоватьТранзакции
	|ИспользоватьТранзакцииПриВыгрузкеДляПлановОбмена
	|КаталогИнформационнойБазыДляПодключения
	|КоличествоОбработанныхОбъектовДляОбновленияСтатуса
	|КоличествоОбъектовДляФоновогоОбмена
	|КоличествоОбъектовДляФоновогоОбменаЗагрузка
	|КоличествоОбъектовНаТранзакцию
	|КоличествоЭлементовВТранзакцииПриВыгрузкеДляПлановОбмена
	|Комментарий
	|КомментарийПриВыгрузкеДанных
	|КомментарийПриЗагрузкеДанных
	|Конвертация
	|НеВыгружатьОбъектыПоСсылкам
	|НепосредственноеЧтениеВИБПриемнике
	|ОбработкиНастройкиВыгрузки
	|ОбработкиНастройкиЗагрузки
	|ОптимизированнаяЗаписьОбъектов
	|ОтслеживатьКоллизииПриЗагрузкеДанных
	|Параметры
	|ПараметрыДопОбработок
	|ПараметрыИнициализированы
	|ПарольИнформационнойБазыДляПодключения
	|ПереданоОбъектовФоновогоОбмена
	|ПолученоОбъектовФоновогоОбмена
	|ПользовательИнформационнойБазыДляПодключения
	|Правила
	|РежимОбмена
	|РежимОтладкиАлгоритмов
	|РезультатВыполненияОтложенныхДвижений
	|СобытияПослеЗагрузкиПараметров
	|СохраненныеНастройки
	|ТаблицаНастройкиПараметров
	|ТаблицаПравилВыгрузки
	|ТаблицаПравилКонвертации
	|ТаблицаПравилОчистки
	|ТипИнформационнойБазыДляПодключения
	|УзелДляОбмена
	|УзелДляФоновогоОбмена
	|УзелОбменаЗагрузкаДанных
	|УзелОбменаЗагрузкаФоновыхДанных
	|УниверсальныйОбменДанными
	|ФайлОбмена
	|ФлагКомментироватьОбработкуОбъектов
	|ФлагОшибки
	|ФлагРежимОтладки
	|ФлагРежимОтладкиОбработчиков
	|ЧислоХранимыхВыгруженныхОбъектовПоТипам
	|ЭтоИнтерактивныйРежим
	|мXMLПравила
	|мАтрибутыФайлаОбмена
	|мБылиПрочитаныПравилаОбменаПриЗагрузке
	|мДатаДокументовДляУстановкиПрефикса
	|мДлинаПрефиксаДокументовПриЗагрузке
	|мИнформацияОПользовательскихПоляхПоискаПриВыгрузкеДанных
	|мИнформацияОПользовательскихПоляхПоискаПриЗагрузкеДанных
	|мКоличествоВыполненныхОтложенныхДвиженийДокументов
	|мНППЗаписанногоВФайл
	|мНомерПоследнегоПоискаПоСсылке
	|мОбработкаДляЗагрузкиДанных
	|мПрефиксДокументовПриЗагрузке
	|мПроверятьЗагруженностьПравилПриВыгрузке
	|мРежимЗагрузкиИнформацииОПравилахОбмена
	|мСписокМакетовПравилОбмена
	|мСчетчикВыгруженныхОбъектов
	|мСчетчикЗагруженныхОбъектов
	|мСчетчикНПП
	|мТаблицаРезультатовЗагрузкиИнформацииОПоляхПоиска
	|мТаблицаРезультатовЗагрузкиИнформацииОПравилахВыгрузкиИКонвертации
	|мФайлПротоколаДанных
	|одТипУзлаXML_КонецЭлемента
	|одТипУзлаXML_НачалоЭлемента
	|одТипУзлаXML_Текст
	|ЕстьГлобальныйОбработчикПередВыгрузкойОбъекта
	|ЕстьГлобальныйОбработчикПослеВыгрузкиОбъекта
	|ЕстьГлобальныйОбработчикПередКонвертациейОбъекта
	|ЕстьГлобальныйОбработчикПередЗагрузкойОбъекта
	|ЕстьГлобальныйОбработчикПослеЗагрузкиОбъекта
	|ВерсияПлатформыПриемника
	|одТипСтрока
	|одТипБулево
	|одТипЧисло
	|одТипДата
	|одТипХранилищеЗначения
	|одТипДвоичныеДанные
	|одТипВидДвиженияНакопления
	|одТипУдалениеОбъекта
	|одТипВидСчета
	|одТипТип
	|одТипСоответствие
	|мТипРегистрСоответствия
	|одСообщения
	|мXMLДокумент
	|мТаблицаПравилКонвертацииСвойств
	|мСтрокаТиповДляПриемника
	|мСоответствиеДопПараметровПоиска
	|мСоответствиеАлгоритмовПоискаЭлементов
	|мСоответствиеПравилКонвертации
	|мСоответствиеТиповИНазваниеОбъектов
	|мСоответствиеПустыхЗначенийТипов
	|мСоответствиеОписаниеТипов
	|мНомерВходящегоСообщения
	|мСоответствиеЗапросовПоПКО
	|мСоответствиеНаличияТиповПриемника
	|мРазрешитьПроведениеДокумента
	|мСтекВызововВыгрузкиДанных
	|мСоответствиеТиповДанныхДляЗагрузки
	|мГлобальныйСтекНеЗаписанныхОбъектов
	|мСоответствиеДанныхДляОбновленияВыгруженныхЭлементов
	|мДатаНачалаВыгрузки
	|мДатаОкончанияВыгрузки
	|мДатаНачалаЗагрузки
	|мДатаОкончанияЗагрузки
	|мДатаНачалаВыполненияОтложенныхОперацийСДокументами
	|мДатаОкончанияВыполненияОтложенныхОперацийСДокументами
	|мМенеджерРегистраСоответствийОбъектов
	|мМенеджерРегистраОтложенныеДвижения
	|мМенеджерРегистраКоллизий
	|мИспользоватьИнформациюОМестеСозданияОбъектовПриЗагрузке
	|мТекущийУровеньВложенностиВыгрузитьПоПравилу
	|мРежимВизуальнойНастройкиОбмена";
	
	Массив = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(СписокПолейТекст, Символы.ПС, Истина); 
	СтруктураСохранения = Новый Структура;
	Для Каждого Эл Из Массив Цикл
		СтруктураСохранения.Вставить(Эл);	
	КонецЦикла;
	
	Возврат СтруктураСохранения;
	
КонецФункции

Например, из списка полей были исключены:

  • Менеджеры
  • МенеджерыДляПлановОбмена
  • ПостроительОтчета
  • мЗапросСтрокРегистраСоответствияОбъектов
  • мЗапросСтрокРегистраОпределенияНаличияВыгрузки
  • мЗапросНаличияСтрокВРегистреСоответствия
  • мЗапросНаличияПустыхДляИсточникаВРегистреСоответствия
  • мЗапросИнформацииОМестеСозданияОбъекта

Далее нужно внести изменения в модуль объекта обработки "ОбменДаннымиXML" и в общий модуль "ПроцедурыОбменаДанными". Чтобы не усложнять пример, мы будем сохранять КЭШ правил только с флагом "Выгрузка". Перейдем в модуль обработки "ОбменДаннымиXML" и добавим следующее:

Процедура ЗагрузитьПравилаОбменаИзКэша(ЗначениеКэша) Экспорт
	
	#Если Клиент Тогда
	Состояние("Выполняется загрузка правил обмена ...");
	#КонецЕсли

	// Инициализируем менеджеры и начальные значения некоторых переменных
    ИнициализироватьМенеджерыИСообщения();
	
	ЕстьГлобальныйОбработчикПередВыгрузкойОбъекта    = Ложь;
	ЕстьГлобальныйОбработчикПослеВыгрузкиОбъекта     = Ложь;	
	ЕстьГлобальныйОбработчикПередКонвертациейОбъекта = Ложь;
	ЕстьГлобальныйОбработчикПередЗагрузкойОбъекта    = Ложь;
	ЕстьГлобальныйОбработчикПослеЗагрузкиОбъекта     = Ложь;
	
	// Заполняем текущие значения полей обработки из КЭШа
	Для Каждого Стр Из ЗначениеКэша Цикл
		ЗначениеИзКэша = Стр.Значение;
		Выполнить(Строка(Стр.Ключ)+"=ЗначениеИзКэша;");
	КонецЦикла;
	
	// После извлечения таблицы правил конвертации в ней были потеряны ссылки
	// на соответствующие строки из таблицы "ТаблицаПравилКонвертации", т.к.
	// эти значения не сериализуются. Восстановим ссылки на строки таблицы
	Для Каждого Стр Из Правила Цикл
		НайденнаяСтрокаПравил = ЭтотОбъект.ТаблицаПравилКонвертации.НайтиСтроки(Новый Структура("Имя", Стр.Ключ));
		Если НайденнаяСтрокаПравил.Количество() > 0 Тогда
			ЭтотОбъект.Правила[Стр.Ключ] = НайденнаяСтрокаПравил.Получить(0);		
		КонецЕсли;             
	КонецЦикла;
	// Аналогично таблице правил конвертации в таблице "Менеджеры" нужно восстановить
	// ссылки на строки таблицы "ТаблицаПравилКонвертации"
	Для Каждого Стр Из Менеджеры Цикл
		НайденнаяСтрокаПравил = ЭтотОбъект.ТаблицаПравилКонвертации.НайтиСтроки(Новый Структура("Источник", Стр.Ключ));
		Если НайденнаяСтрокаПравил.Количество() > 0 Тогда
			Стр.Значение.ПКО = НайденнаяСтрокаПравил.Получить(0);		
		КонецЕсли;
	КонецЦикла;
	
	// Вызываем событие после загрузки правил обмена
	ТекстСобытияПослеЗагрузкиПравилОбмена = "";
	Если Конвертация.Свойство("ПослеЗагрузкиПравилОбмена", ТекстСобытияПослеЗагрузкиПравилОбмена)
		И Не ПустаяСтрока(ТекстСобытияПослеЗагрузкиПравилОбмена) Тогда
		
		Попытка
			Выполнить(ТекстСобытияПослеЗагрузкиПравилОбмена);
		Исключение
			СтрокаСообщенияОбОшибке = ЗаписатьИнформациюОбОшибкеОбработчикиКонвертации(75, ОписаниеОшибки(), "ПослеЗагрузкиПравилОбмена (конвертация)");
			Отказ = Истина;
			
			Если Не ФлагРежимОтладки Тогда
				ВызватьИсключение СтрокаСообщенияОбОшибке;
			КонецЕсли;
			
		КонецПопытки;	
		
	КонецЕсли;
	
	// Инициализируем начальные значения параметров
	ИнициализироватьПервоначальныеЗначенияПараметров();
	
КонецПроцедуры
Думаю, что о назначении процедуры ясно из ее названия, но обратите внимание на до заполнение таблиц "Правила" и "Менеджеры". Если запускать стандартную процедуру чтения правил обмена, в эти таблицы будут содержать ссылки на строки другой таблицы "ТаблицаПравилКонвертации". После восстановления этих таблиц из КЭШа ссылки конечно же теряются, т.к. не поддаются сериализации. Выход из ситуации простой - нужно до заполнить восстановленные таблицы заново, что мы и сделали.
Функция ПолучитьПравилаОбменаДляСохраненияВКэш() Экспорт
	
	// Инициализируем структуру свойств для сохранения в КЭШ
	СтруктураСохранения = РегистрыСведений.yy_НастройкиКэшированияПравил.ПолучитьСтруктуруСохраненияДанных();
	
	// Заполняем структуру
	ЗаполнитьЗначенияСвойств(СтруктураСохранения, ЭтотОбъект);	
	ПоляЗаполненияПрисваиванием = 
	"ЕстьГлобальныйОбработчикПередВыгрузкойОбъекта
	|ЕстьГлобальныйОбработчикПослеВыгрузкиОбъекта
	|ЕстьГлобальныйОбработчикПередКонвертациейОбъекта
	|ЕстьГлобальныйОбработчикПередЗагрузкойОбъекта
	|ЕстьГлобальныйОбработчикПослеЗагрузкиОбъекта
	|ВерсияПлатформыПриемника
	|одТипСтрока
	|одТипБулево
	|одТипЧисло
	|одТипДата
	|одТипХранилищеЗначения
	|одТипДвоичныеДанные
	|одТипВидДвиженияНакопления
	|одТипУдалениеОбъекта
	|одТипВидСчета
	|одТипТип
	|одТипСоответствие
	|мТипРегистрСоответствия
	|одСообщения
	|мXMLДокумент
	|мТаблицаПравилКонвертацииСвойств
	|мСтрокаТиповДляПриемника
	|мСоответствиеДопПараметровПоиска
	|мСоответствиеАлгоритмовПоискаЭлементов
	|мСоответствиеПравилКонвертации
	|мСоответствиеТиповИНазваниеОбъектов
	|мСоответствиеПустыхЗначенийТипов
	|мСоответствиеОписаниеТипов
	|мНомерВходящегоСообщения
	|мСоответствиеЗапросовПоПКО
	|мСоответствиеНаличияТиповПриемника
	|мРазрешитьПроведениеДокумента
	|мСтекВызововВыгрузкиДанных
	|мСоответствиеТиповДанныхДляЗагрузки
	|мГлобальныйСтекНеЗаписанныхОбъектов
	|мСоответствиеДанныхДляОбновленияВыгруженныхЭлементов
	|мДатаНачалаВыгрузки
	|мДатаОкончанияВыгрузки
	|мДатаНачалаЗагрузки
	|мДатаОкончанияЗагрузки
	|мДатаНачалаВыполненияОтложенныхОперацийСДокументами
	|мДатаОкончанияВыполненияОтложенныхОперацийСДокументами
	|мМенеджерРегистраСоответствийОбъектов
	|мМенеджерРегистраОтложенныеДвижения
	|мМенеджерРегистраКоллизий
	|мИспользоватьИнформациюОМестеСозданияОбъектовПриЗагрузке
	|мТекущийУровеньВложенностиВыгрузитьПоПравилу
	|мРежимВизуальнойНастройкиОбмена";
	МассивПолейПрисваивания = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ПоляЗаполненияПрисваиванием, Символы.ПС, Истина); 
	Для Каждого Поле Из МассивПолейПрисваивания Цикл
		Выполнить("СтруктураСохранения."+Поле+" = "+Поле+";");	
	КонецЦикла;
	
	Возврат СтруктураСохранения;
	
КонецФункции
В функции "ПолучитьПравилаОбменаДляСохраненияВКэш" мы инициализируем пустую структуру, а потом заполняем ее текущими значениями из обработки. Извините за большой листинг, но все же реализация заполнения важная часть и не хотелось бы ее выпускать из виду.
В принципе у нас уже все готово для работы с КЭШем правил конвертации. Осталось лишь его задействовать при запуске обмена. Для этого в общем модуле "ПроцедурыОбменаДанными" добавим в процедуру "УстановитьПараметрыДляВыгрузкиДанныхXML" следующий код:
Процедура УстановитьПараметрыДляВыгрузкиДанныхXML(ОбработкаОбменаДаннымиXML, СтруктураНастроекОбменаДанными, ЭтоВыгрузкаИзТекущейИБ = Истина) Экспорт
	
	ДанныеНастройки = СтруктураНастроекОбменаДанными.ДанныеНастройки;
	
	ОбработкаОбменаДаннымиXML.РежимОбмена = "Выгрузка";
	
	Если ЭтоВыгрузкаИзТекущейИБ Тогда
		ТекстПравил = ДанныеНастройки.ПравилаОбмена.Получить();
	Иначе
		ТекстПравил = ДанныеНастройки.ПравилаОбменаДляПриемника.Получить();
	КонецЕсли;
	
	// YPermitin - Проверяем наличие КЭШа правил конвертации
	// Если КЭШ уже сохранен, то используем его
	// Типовой код:
	//Если НЕ ПустаяСтрока(ТекстПравил) Тогда
	//
	//	ОбработкаОбменаДаннымиXML.ЗагрузитьПравилаОбмена(ТекстПравил, "Строка");
	//	
	//КонецЕсли;
	КэшПравилОбмена = РегистрыСведений.yy_НастройкиКэшированияПравил.ПолучитьКэш(ДанныеНастройки.УзелИнформационнойБазы, Истина);
	Если КэшПравилОбмена.ЗначениеКэша = Неопределено Тогда	
		Если НЕ ПустаяСтрока(ТекстПравил) Тогда	
			ОбработкаОбменаДаннымиXML.ЗагрузитьПравилаОбмена(ТекстПравил, "Строка");		
		КонецЕсли;
		Если КэшПравилОбмена.ИспользоватьКэш Тогда
			СтруктураСохранения = ОбработкаОбменаДаннымиXML.ПолучитьПравилаОбменаДляСохраненияВКэш();
			РегистрыСведений.yy_НастройкиКэшированияПравил.УстановитьКэш(ДанныеНастройки.УзелИнформационнойБазы, Истина, СтруктураСохранения);
		КонецЕсли;
	Иначе
		ОбработкаОбменаДаннымиXML.ЗагрузитьПравилаОбменаИзКэша(ПолучитьИзВременногоХранилища(КэшПравилОбмена.ЗначениеКэша));
	КонецЕсли;
	// YPermitin
	
	ОбработкаОбменаДаннымиXML.мПроверятьЗагруженностьПравилПриВыгрузке = Ложь;
	
	// .....

Посмотрим результат

Итак, настройки в регистра "Настройки кэширования правил" сделаны, все необходимые изменения внесены в конфигурацию, а значит время тестирования! Выполним первый запуск выгрузки данных, а затем запустим его еще раз, но с уже сохраненным КЭШем правил конвертации. Замеры времени покажут, чего мы добились.

До оптимизации замер времени выполнения чтения правил конвертации из XML-файла следующий:

Замер времени до оптимизации

Итого на чтение правил было затрачено 152,6 секунды (~2,5 минуты). А теперь посмотрим сколько времени займет эта же операция при использовании КЭШа правил конвертации:

После оптимизации

Всего 8 секунд! Похоже я Вас обманул, когда написал в заголовке статьи, что оптимизация даст эффект ускорения чтения правил конвертации в 20 раз, ведь ускорили мы его всего лишь в 19 раз! =)

В продолжение

Итак, оптимизация проведена успешно! Мы добились значительного ускорения чтения правил конвертации. Такой подход использовался мной при решении реальных задач. Если развивать тему, то дальше можно сделать автоматическую очистку КЭШа при загрузке новой версии правил конвертации, добавить новый вид транспорта сообщений в УПП 1.3 через веб-сервисы, уменьшить периодичность обмена, сделать отложенную загрузку и выгрузку сообщений обмена по очереди поступления, реализовать поддержку пакетного обмена данными, минимизировать влияние блокировок при обмене, но...меня понесло! Все это уже совсем другая история и поговорим об этом в следующий раз!

Напоследок скажу, что данный подход к оптимизации чтения правил конвертации подходит не только для устаревших механизмов обмена, которые присутствуют в УПП 1.3, УТ 10.3 и др. старых версиях конфигураций, но и для новый конфигураций как ERP 2.0, УТ 11.1, БП 3.0 и др. Конечно нужно вносить изменения иначе, но принцип тот же. И даже наличие модулей БСП ничего не поменяет.

Спасибо за внимание!

Вопросы и пожелания оставляйте в комментариях!


comments powered by Disqus