Немного теории: Конкатенация (соединение строк). Казалось бы - ну что может быть проще и однозначнее? Ан нет. Выражение T = "А"+"Б"; (если оно не вычислено на этапе компиляции/разбора) требует выделения памяти для "А", памяти для "Б", анализа длин "А" и "Б", выделение памяти для T, копирование первой строки, копирование второй строки. Это медленно, особенно если в цикле дописывается кусочек в конец строки.
В "нормальных" системах, например в .NET от этого можно уйти используя так называемые StringBuilder - это специальный объект, который более эффективно выделяет память (крупными блоками) и не копирует зря строки. По сути это поток (stream) который используется для записи в память, как в файл. А вот в 1С такого нет. Фиг вам товарищи, а не эффективная работа со строками Но фиг только тем у кого хитрости мало, а для остальных есть варианты. ТекстовыйДокумент
Оказывается, что метод ДобавитьСтроку() для типа ТекстовыйДокумент для больших строк работает гораздо эффективнее чем тупая конкатенация. Возможно, это связано с тем, что этот тип - обёртка к текстовому редактору, встроенному в 1С. Кстати, этот редактор для простых текстовых файлов файлов мне нравится гораздо больше, чем например, notepad или редактор Visual Studio - он позволяет бодрее работать с большими текстами, как в длину, так и в ширину.
Но! У этого способа есть недостаток - в 8.0 и 8.1 он не доступен на сервере, т.к. считается "интерфейсным". Обидно. Но это заставляет искать нас более эффективный способ: ЗаписьXML
Опа! А при чём здесь XML? Правильно, XML нам не нужен. Но важно, что тип ЗаписьXML представляет собой как раз обёртку над последовательной записью в поток. А если учесть, что он позволяет формировать результат в память в виде строки, а не только в файл, то это уже готовый кандидат на замену StringBuilder. Осталось только упомянуть, что он позволяет дозаписывать в "XML" всё что угодно при помощи метода ЗаписатьБезОбработки().
Результаты забегов
У меня на тестовой среде получилось примерно следующее время:
1. Конкатенация - 24 секунды
2. Текстовый документ 1,5 секунды
3. ЗаписьXML - около 0,4 секунды
Пожалуй, начнем сразу с практического примера.
В справочник Контрагенты нам необходимо заносить информацию о поставщиках, покупателях, банках, налоговых органах, различных фондах и пр. Для каждого вида контрагента нас интересует разная информация.
Создадим функцию, возвращающую список «важных» реквизитов в зависимости от вида контрагента:
Где же ее правильнее разместить?
Напрашивается вариант - в процедуре Модуля объекта «ПередЗаписью()». Тем самым мы на этапе записи будем контролировать правильность заполнения нужных нам реквизитов. С точки зрения создания, изменения элемента справочника, нас все устраивает. Но если нам необходимо, чтобы некоторые менеджеры заносились контрагентов в ИБ без контроля, а спустя какое-то время мы будем выполнять проверку на корректность заполнения данных в справочнике. Тогда нужно будет написать обработку. И в этой обработке, перебирая элементы, проверять заполнение реквизитов. Т.о. эту функцию придется разместить в коде обработки. А это получается дублирование кода, со всеми вытекающими проблемами. Можно получать объект каждого элемента, обращаться к функции, расположенной в его Модуле объекта. Но это будет дополнительные обращения к БД, тогда как в обработке нам достаточно только ссылок.
Можно выйти из этой ситуации создав Общий модуль «РаботаСКонтрагентами» и разместить в нем функцию возвращающую список реквизитов для проверки. В этом случае будем обращаться так «РаботаСКонтрагентами.ПолучитьСписокВажныхРеквизитов(ВидКонтрагента)».
Но! На платформе 8.2 как раз для решения подобной задачи и был создан Модуль менежера. Там и разместим нашу функцию. А обращаться мы будем: «Справочники.Контрагенты.ПолучитьСписокВажныхРеквизитов(ВидКонтрагента)».
Т.о. на ряду с предопределенными методами, мы можем самостоятельно разработать свои процедуры и обращаться к ним как методам Менеджера объекта, через точку. У нас отпадает необходимость создавать «тематические» внешние модули такие как «Работа с Контрагентами», «Процедуры Номенклатуры»...
Обратимся теперь к теории, чтобы «разложить все по полочкам».
Руководство разработчика дает нам следующее описание: «Модуль менеджера существует у всех прикладных объектов и предназначен для управления этим объектом как объектом конфигурации. Модуль менеджера позволяет расширить функциональность менеджеров за счет введения процедур и функций на встроенном языке. Фактически это позволяет описать методы для объекта конфигурации, которые относятся не к конкретному экземпляру объекта базы данных, а к самому объекту конфигурации». Именно это мы и разобрали в нашем практическом примере.
Отобразим иерархию классов прикладных объектов на примере Справочников:
Т.е. мы видим, что появление «Модуля менеджера объекта» логично расширяет свойства класса СправочникМенеджер, так же как экспортные процедуры «Модуля объекта» расширяют методы класса СправочникОбъект. Нужно ли было создавать «Модуль прикладного объекта Справочники (Документы, Перечисления)». Наверное нет. Достаточно трудно придумать какие-либо задачи для единой обработки всех видов справочников.
Кроме возможности расширения методов класса, в модуле менеджера существует предопределенная процедура События . Она возникает на сервере перед стандартным формированием списка при вводе по строке, автоподборе текста и быстром выборе, а также при выполнении метода «ПолучитьДанныеВыбора()».
Так же хочу обратить внимание. При использовании конструктора печати прикладного объекта, платформа расположит процедуру формирования табличного документа непосредственно в Модуле менеджера. И это логично. Теперь, чтобы получить табличный документ элемента справочника нет необходимости получать объект. Достаточно кода: .