HelpF.pro

Сравнение: Конкатенация, ТекстовыйДокумент, ЗаписьXML

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

//Создаём базовую строчку:
БазоваяСтрока = "";
Для Сч = 1 по ДлинаДобавляемогоКуска-1 Цикл
БазоваяСтрока = БазоваяСтрока + "Ы";
КонецЦикла;
БазоваяСтрокаПС = БазоваяСтрока + Символы.ПС;

//Способ 1. Добавление строк к концу строки
Сообщить("Способ 1. Добавление строк к концу строки - Начало " + Строка(ТекущаяДата()));
ФиктивныйРезультат = 0;
Для СчИтераций = 1 по КоличествоИтераций Цикл
Состояние("Способ 1. Добавление строк к концу строки - " + Строка(СчИтераций));
СтрокаРезультат = "";
Для СчДобавлений = 1 по (ОбщаяДлинаСтроки/ДлинаДобавляемогоКуска) Цикл
СтрокаРезультат = СтрокаРезультат + БазоваяСтрокаПС;
КонецЦикла;
ФиктивныйРезультат = ФиктивныйРезультат + СтрДлина(СтрокаРезультат);
ОбработкаПрерыванияПользователя();
КонецЦикла;
Сообщить("Фиктивный результат = " + Строка(ФиктивныйРезультат));
Сообщить("Способ 1. Добавление строк к концу строки - Окончание " + Строка(ТекущаяДата()));

//Способ 2. Добавление строк в текстовый документ
Сообщить("Способ 2. Добавление строк в текстовый документ - Начало " + Строка(ТекущаяДата()));
ФиктивныйРезультат = 0;
Для СчИтераций = 1 по КоличествоИтераций Цикл
Состояние("Способ 2. Добавление строк в текстовый документ - " + Строка(СчИтераций));
ТекстПостроитель = Новый ТекстовыйДокумент;
Для СчДобавлений = 1 по (ОбщаяДлинаСтроки/ДлинаДобавляемогоКуска) Цикл
ТекстПостроитель.ДобавитьСтроку(БазоваяСтрока); //ПС добавляется сам
КонецЦикла;
СтрокаРезультат = ТекстПостроитель.ПолучитьТекст();
ФиктивныйРезультат = ФиктивныйРезультат + СтрДлина(СтрокаРезультат);
ОбработкаПрерыванияПользователя();
КонецЦикла;
Сообщить("Фиктивный результат = " + Строка(ФиктивныйРезультат));
Сообщить("Способ 2. Добавление строк в текстовый документ - Окончание " + Строка(ТекущаяДата()));

//Способ 3. Создание через ЗаписьXML
Сообщить("Способ 3. Создание через ЗаписьXML - Начало " + Строка(ТекущаяДата()));
ФиктивныйРезультат = 0;
Для СчИтераций = 1 по КоличествоИтераций Цикл
Состояние("Способ 3. Создание через ЗаписьXML - " + Строка(СчИтераций));
ТекстПостроитель = Новый ЗаписьXML;
ТекстПостроитель.УстановитьСтроку();
Для СчДобавлений = 1 по (ОбщаяДлинаСтроки/ДлинаДобавляемогоКуска) Цикл
ТекстПостроитель.ЗаписатьБезОбработки(БазоваяСтрокаПС);
КонецЦикла;
СтрокаРезультат = ТекстПостроитель.Закрыть();
ФиктивныйРезультат = ФиктивныйРезультат + СтрДлина(СтрокаРезультат);
ОбработкаПрерыванияПользователя();
КонецЦикла;
Сообщить("Фиктивный результат = " + Строка(ФиктивныйРезультат));
Сообщить("Способ 3. Создание через ЗаписьXML - Окончание " + Строка(ТекущаяДата()));
//ЗЫ: данный код проверен в 8.2 )


Результаты забегов
У меня на тестовой среде получилось примерно следующее время:
1. Конкатенация - 24 секунды
2. Текстовый документ 1,5 секунды
3. ЗаписьXML - около 0,4 секунды

Пишет Alexander Speshilov
Опубликовано на сайте: https://HelpF.pro
Прямая ссылка: https://HelpF.pro/faq/view/1519.html