- А что это такое?
Программист Артём заметил у программиста Васи такой код:
Для Каждого КоллекцияМетаданных Из СтрРазделить("Справочники,Документы", ",") Цикл //... КонецЦикла;
Василий рассказал Артёму, что таким образом он быстро создал наполненный массив. Сделав код более коротким. Раньше было так:
КоллекцииМетаданных = Новый Массив; КоллекцииМетаданных.Добавить("Справочники"); КоллекцииМетаданных.Добавить("Документы"); Для Каждого КоллекцияМетаданных Из КоллекцииМетаданных Цикл //... КонецЦикла;
Артём понял задумку Василия. Ведь никто так хорошо не поймёт ленивого программиста, как другой ленивый программист. Но заметил, что он бы делал немного по-другому.
Для Каждого КоллекцияМетаданных Из Новый Структура("Справочники,Документы") Цикл //... КонецЦикла;
- Так оптимальнее - сказал программист Артём, рассказывая что-то про внутренние механизмы платформы...
- А вот и нет! - не согласился программист Вася, рассказывая что-то про оптимизацию метода СтрРазделить...
Так всё и началось.
Быстрое создание наполненных коллекций
Помните, как бывает в других языках программирования?
C#
string[] seasons = {"Winter", "Spring", "Summer", "Autumn"};
Java
String[] seasons = {"Winter", "Spring", "Summer", "Autumn"};
JavaScript
var seasons = ["Winter", "Spring", "Summer", "Autumn"];
Python
seasons = ['Winter', 'Spring', 'Summer', 'Autumn']
Как же это бывает удобно - создать сразу наполненный значениями массив. Жаль, что в 1С такое не предусмотрено.
Но хорошо, что в нашем примере потребовались строковые массивы. Для этого в 1С есть способы:
СтрРазделить()
РезультатСоздания = СтрРазделить("Понедельник,Вторник,Среда,Четверг,Пятница,Суббота,Воскресенье", ",");
Кто-то скажет, что это не совсем то, что нам нужно — парсить строку для того, чтобы получить массив, значения которого заранее известны. Однако, на практике такой подход встречается довольно часто.
Управление торговлей 11.4.9.91 (спойлер):
ОбязательныеСтандартныеРеквизиты = СтрРазделить("Период,Регистратор,ВидДвижения,Активность", ","); Для каждого РеквизитРегистра Из Коллекция.СтандартныеРеквизиты Цикл
НаборГруппДанныхСМаркировкой = СтрРазделить("ПоДокументу,ПоФакту,Бой,Брак,Излишки,Недостача", ","); НаборГруппДанныхСПрослеживанием = СтрРазделить("ПоДокументу,ПоФакту,Бой,Брак,Излишки,Недостача", ",");
Бухгалтерия предприятия КОРП 3.0.72.70 (спойлер):
СвойстваНастроек = СтрРазделить("Использование, ВидСравнения, Значение", ", ", Ложь); Для Каждого СвойствоНастройки Из СвойстваНастроек Цикл
Для каждого ВидПериода Из СтрРазделить("ДатаПроизводства,СрокГодности",",") Цикл
И тут можно вспомнить, что метод СтрРазделить() появился только в версии 8.3.6. Как же раньше программисты могли одной строчкой кода создать наполненный массив?
РазложитьСтрокуВМассивПодстрок()
Выглядит это так:
РезультатСоздания = РазложитьСтрокуВМассивПодстрок("Понедельник,Вторник,Среда,Четверг,Пятница,Суббота,Воскресенье", ",");
Да, ещё один парсинг. Только на основе БСПшной функции, которая существует в типовых испокон веков.
Удивительно, но до сих пор можно встретить примеры использования даже в свежих типовых конфигурациях:
Бухгалтерия предприятия КОРП 3.0.72.70 (спойлер) :
Для Каждого ЭлтКлюч Из СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок("_ДатаПрмЭ,_ДатаПрмБ,_ДатаДокОтв", ",") Цикл СЗ.Добавить(ЭлтКлюч, Формат(Ответ[ЭлтКлюч], "ДФ=yyyyMMdd")); КонецЦикла;
Для Каждого Элт Из СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок("А%Б%В", "%") Цикл
Зарплата и управление персоналом 3.1.11.106 (спойлер) :
Для Каждого ЭлтКлюч Из СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок("_ДатаПрмЭ,_ДатаПрмБ,_ДатаДокОтв", ",") Цикл
Для Каждого Элт Из СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок("{{,{", ",") Цикл
Что лучше использовать в таком случае? Думаю, вопрос очевиден, учитывая, что платформенный метод, как заявляют разработчики, намного быстрее БСПшного. Так ли это? Проверим далее. Но не стоит забывать, что они не совсем идентичны. И об этом писалось в статье Чем расщепить или "СтрРазделить() VS РазложитьСтрокуВМассивПодстрок()" ?
Новый Структура()
Да, умельцы-программисты использовали стандартный конструктор структуры как способ создавать наполненную коллекцию.
И да, этот способ имеет ряд ограничений:
-
Результат будет структурой, а не массивом.
-
Все значения должны соответствовать правилам именования 1С.
-
Разделитель только запятая.
Все эти минусы, зачастую, не создают проблем и разработчики с удовольствием применяют данный подход.
Ну и, как обычно, примеры из типовых:
Управление торговлей 11.4.9.91 (спойлер):
Для Каждого КлючИЗначение Из Новый Структура("Данные, Источники, Приемники, РасчетныеПартии") Цикл
ПоляРесурсов = " |Стоимость, СтоимостьБезНДС, ПостояннаяРазница, ВременнаяРазница, |СтоимостьРегл, ДопРасходы, ДопРасходыБезНДС, |СтоимостьЗабалансовая, Трудозатраты, ПостатейныеПостоянныеСНДС, ПостатейныеПеременныеСНДС, |ПостатейныеПостоянныеБезНДС, ПостатейныеПеременныеБезНДС, |СтоимостьЗабалансоваяРегл, ДопРасходыРегл, ТрудозатратыРегл, ПостатейныеПостоянныеРегл, ПостатейныеПеременныеРегл, |СтоимостьУпр, ДопРасходыУпр, ТрудозатратыУпр, ПостатейныеПостоянныеУпр, ПостатейныеПеременныеУпр"; Для Каждого КлючИЗначение Из Новый Структура(ПоляРесурсов) Цикл Запись[КлючИЗначение.Ключ] = - ДанныеДвижения[КлючИЗначение.Ключ]; КонецЦикла;
ВозвращаемыеСвойства = "НетЗаданий, ПерезапускОбновления, ПерезапускОбновленияСНачала, НаборПорций, |НовыйПоследнийОбновленныйЭлемент, НачальноеОбновлениеЗавершено, ТекстОшибкиЗавершения"; Для Каждого КлючИЗначение Из Новый Структура(ВозвращаемыеСвойства) Цикл
Бухгалтерия предприятия КОРП 3.0.72.70 (спойлер) :
КолонкиДоходов = "ЦенныеБумагиИтогоСуммаДоходов,ЦенныеБумагиСуммаДохода"; Для Каждого КолонкаДохода Из Новый Структура(КолонкиДоходов) Цикл
КолонкиРасходов = "ЦенныеБумагиИтогоСуммаРасходовКВычету,ЦенныеБумагиСуммаРасходовУменьшающаяДоходы,ЦенныеБумагиИтогоСуммаУбытка"; Для Каждого КолонкаРасхода Из Новый Структура(КолонкиРасходов) Цикл
И тут становится уже интереснее. А что быстрее: создать массив при помощи парсинга строки СтрРазделить() или же создать структуру стандартным конструктором Новый Структура() ? Чего гадать, когда можно проверить!
Разработка инструмента
Под этим спойлером подробная информация, как делался инструмент:
Для этого создаём простенький отчет.
В СКД указываем набор данных объект с колонками, которые нужны будут для анализа:
В параметрах указываем количество "подходов", количество созданий за один подход, ну и сами методы:
Накидываем ресурсы:
И делаем простой вывод диаграммы с детальными записями:
В ПриКомпоновкеРезультата() будем делать все манипуляции.
Для начала отключим стандартную обработку и очистим результат:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) СтандартнаяОбработка = Ложь; ДокументРезультат.Очистить(); КонецПроцедуры
Получим параметры из настроек (добавим функцию):
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) СтандартнаяОбработка = Ложь; ДокументРезультат.Очистить(); ПараметрыВыполнения = ПараметрыВыполнения(); КонецПроцедуры Функция ПараметрыВыполнения() ПараметрыВыполнения = Новый Структура; НастройкиКомпоновки = КомпоновщикНастроек.ПолучитьНастройки(); ПараметрыВыполнения.Вставить("НастройкиКомпоновки", НастройкиКомпоновки); Для Каждого ПараметрКомпоновщика Из НастройкиКомпоновки.ПараметрыДанных.Элементы Цикл Если ПараметрКомпоновщика.Использование Тогда ПараметрыВыполнения.Вставить(ПараметрКомпоновщика.Параметр, ПараметрКомпоновщика.Значение); КонецЕсли; КонецЦикла; Возврат ПараметрыВыполнения; КонецФункции
Подготовим функцию для замеров:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) СтандартнаяОбработка = Ложь; ДокументРезультат.Очистить(); ПараметрыВыполнения = ПараметрыВыполнения(); ДанныеЗамеров = ДанныеЗамеров(ПараметрыВыполнения); КонецПроцедуры Функция ДанныеЗамеров(ПараметрыВыполнения) ДанныеЗамеров = Новый ТаблицаЗначений; //Просто заполним структуру таблицы из полей описанного нами набора схемы компоновки Для Каждого ТекущееПоле Из СхемаКомпоновкиДанных.НаборыДанных.Получить(0).Поля Цикл ДанныеЗамеров.Колонки.Добавить(ТекущееПоле.Поле, ТекущееПоле.ТипЗначения, ТекущееПоле.Заголовок); КонецЦикла; Если НЕ ЗначениеЗаполнено(ПараметрыВыполнения.Методы) Тогда Возврат ДанныеЗамеров; КонецЕсли; //Здесь будем замерять Возврат ДанныеЗамеров; КонецФункции
И сразу же не забудем вывести результат в табличный документ.
Для удобства будем использовать процедуру, описанную в статье "Меньше копипаста!", или как Вася универсальную процедуру писал
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) СтандартнаяОбработка = Ложь; ДокументРезультат.Очистить(); ПараметрыВыполнения = ПараметрыВыполнения(); ДанныеЗамеров = ДанныеЗамеров(ПараметрыВыполнения); ВнешниеНаборыДанных = Новый Структура("Результат", ДанныеЗамеров); СкомпоноватьРезультатОтчета(ДокументРезультат, СхемаКомпоновкиДанных, ПараметрыВыполнения.НастройкиКомпоновки, ДанныеРасшифровки, ВнешниеНаборыДанных); КонецПроцедуры
Всё, база готова. Уже сейчас отчёт может выводиться, хоть и без замеров. Пора заняться ими!
Подготовим циклы. Будем сначала выполнять подходы, а потом для каждого подхода будем выполнять каждый метод:
Функция ДанныеЗамеров(ПараметрыВыполнения) ДанныеЗамеров = Новый ТаблицаЗначений; //Просто заполним структуру таблицы из полей описанного нами набора схемы компоновки Для Каждого ТекущееПоле Из СхемаКомпоновкиДанных.НаборыДанных.Получить(0).Поля Цикл ДанныеЗамеров.Колонки.Добавить(ТекущееПоле.Поле, ТекущееПоле.ТипЗначения, ТекущееПоле.Заголовок); КонецЦикла; Если НЕ ЗначениеЗаполнено(ПараметрыВыполнения.Методы) Тогда Возврат ДанныеЗамеров; КонецЕсли; Для ТекущийПодход = 1 По ПараметрыВыполнения.КоличествоПодходов Цикл Для Каждого ТекущийМетод Из ПараметрыВыполнения.Методы Цикл КонецЦикла; КонецЦикла; Возврат ДанныеЗамеров; КонецФункции
Добавим новую строчку замера и заполним текущими данными
Функция ДанныеЗамеров(ПараметрыВыполнения) ДанныеЗамеров = Новый ТаблицаЗначений; //Просто заполним структуру таблицы из полей описанного нами набора схемы компоновки Для Каждого ТекущееПоле Из СхемаКомпоновкиДанных.НаборыДанных.Получить(0).Поля Цикл ДанныеЗамеров.Колонки.Добавить(ТекущееПоле.Поле, ТекущееПоле.ТипЗначения, ТекущееПоле.Заголовок); КонецЦикла; Если НЕ ЗначениеЗаполнено(ПараметрыВыполнения.Методы) Тогда Возврат ДанныеЗамеров; КонецЕсли; Для ТекущийПодход = 1 По ПараметрыВыполнения.КоличествоПодходов Цикл Для Каждого ТекущийМетод Из ПараметрыВыполнения.Методы Цикл ТекущиеДанные = ДанныеЗамеров.Добавить(); ТекущиеДанные.Метод = ТекущийМетод.Значение; ТекущиеДанные.ТекущийПодход = ТекущийПодход; ТекущиеДанные.КоличествоСозданий = ПараметрыВыполнения.КоличествоСозданий; КонецЦикла; КонецЦикла; Возврат ДанныеЗамеров; КонецФункции
Пока пропустим ненадолго момент с самими замерами. Представим, что они выполнены. Теперь нам нужно рассчитать количество созданий экземпляра коллекции за одну миллисекунду:
Функция ДанныеЗамеров(ПараметрыВыполнения) ДанныеЗамеров = Новый ТаблицаЗначений; //Просто заполним структуру таблицы из полей описанного нами набора схемы компоновки Для Каждого ТекущееПоле Из СхемаКомпоновкиДанных.НаборыДанных.Получить(0).Поля Цикл ДанныеЗамеров.Колонки.Добавить(ТекущееПоле.Поле, ТекущееПоле.ТипЗначения, ТекущееПоле.Заголовок); КонецЦикла; Если НЕ ЗначениеЗаполнено(ПараметрыВыполнения.Методы) Тогда Возврат ДанныеЗамеров; КонецЕсли; Для ТекущийПодход = 1 По ПараметрыВыполнения.КоличествоПодходов Цикл Для Каждого ТекущийМетод Из ПараметрыВыполнения.Методы Цикл ТекущиеДанные = ДанныеЗамеров.Добавить(); ТекущиеДанные.Метод = ТекущийМетод.Значение; ТекущиеДанные.ТекущийПодход = ТекущийПодход; ТекущиеДанные.КоличествоСозданий = ПараметрыВыполнения.КоличествоСозданий; Если ТекущиеДанные.ОбщееВремяСозданий > 0 Тогда ТекущиеДанные.КоличествоСозданийЗаМилисекунду = Окр(ТекущиеДанные.КоличествоСозданий / ТекущиеДанные.ОбщееВремяСозданий, 2); Иначе ТекущиеДанные.КоличествоСозданийЗаМилисекунду = ТекущиеДанные.КоличествоСозданий; КонецЕсли; КонецЦикла; КонецЦикла; Возврат ДанныеЗамеров; КонецФункции
База готова. Теперь просто выполним замеры каждого метода.
Функция ДанныеЗамеров(ПараметрыВыполнения) ДанныеЗамеров = Новый ТаблицаЗначений; //Просто заполним структуру таблицы из полей описанного нами набора схемы компоновки Для Каждого ТекущееПоле Из СхемаКомпоновкиДанных.НаборыДанных.Получить(0).Поля Цикл ДанныеЗамеров.Колонки.Добавить(ТекущееПоле.Поле, ТекущееПоле.ТипЗначения, ТекущееПоле.Заголовок); КонецЦикла; Если НЕ ЗначениеЗаполнено(ПараметрыВыполнения.Методы) Тогда Возврат ДанныеЗамеров; КонецЕсли; Для ТекущийПодход = 1 По ПараметрыВыполнения.КоличествоПодходов Цикл Для Каждого ТекущийМетод Из ПараметрыВыполнения.Методы Цикл ТекущиеДанные = ДанныеЗамеров.Добавить(); ТекущиеДанные.Метод = ТекущийМетод.Значение; ТекущиеДанные.ТекущийПодход = ТекущийПодход; ТекущиеДанные.КоличествоСозданий = ПараметрыВыполнения.КоличествоСозданий; Если ТекущиеДанные.Метод = "СтрРазделить" Тогда ЗамеритьМетодСтрРазделить(ТекущиеДанные); ИначеЕсли ТекущиеДанные.Метод = "НовыйСтруктура" Тогда ЗамеритьМетодНовыйСтруктура(ТекущиеДанные); ИначеЕсли ТекущиеДанные.Метод = "РазложитьСтрокуВМассивПодстрок" Тогда ЗамеритьМетодРазложитьСтрокуВМассивПодстрок(ТекущиеДанные); КонецЕсли; Если ТекущиеДанные.ОбщееВремяСозданий > 0 Тогда ТекущиеДанные.КоличествоСозданийЗаМилисекунду = Окр(ТекущиеДанные.КоличествоСозданий / ТекущиеДанные.ОбщееВремяСозданий, 2); Иначе ТекущиеДанные.КоличествоСозданийЗаМилисекунду = ТекущиеДанные.КоличествоСозданий; КонецЕсли; КонецЦикла; КонецЦикла; Возврат ДанныеЗамеров; КонецФункции
Ну и, собственно, сами методы:
Процедура ЗамеритьМетодСтрРазделить(ТекущиеДанные) НачалоЗамера = ТекущаяУниверсальнаяДатаВМиллисекундах(); Для ТекущееСоздание = 1 По ТекущиеДанные.КоличествоСозданий Цикл РезультатСоздания = СтрРазделить("Понедельник,Вторник,Среда,Четверг,Пятница,Суббота,Воскресенье", ","); КонецЦикла; ТекущиеДанные.ОбщееВремяСозданий = ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоЗамера; КонецПроцедуры Процедура ЗамеритьМетодРазложитьСтрокуВМассивПодстрок(ТекущиеДанные) НачалоЗамера = ТекущаяУниверсальнаяДатаВМиллисекундах(); Для ТекущееСоздание = 1 По ТекущиеДанные.КоличествоСозданий Цикл РезультатСоздания = РазложитьСтрокуВМассивПодстрок("Понедельник,Вторник,Среда,Четверг,Пятница,Суббота,Воскресенье", ","); КонецЦикла; ТекущиеДанные.ОбщееВремяСозданий = ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоЗамера; КонецПроцедуры Процедура ЗамеритьМетодНовыйСтруктура(ТекущиеДанные) НачалоЗамера = ТекущаяУниверсальнаяДатаВМиллисекундах(); Для ТекущееСоздание = 1 По ТекущиеДанные.КоличествоСозданий Цикл РезультатСоздания = Новый Структура("Понедельник,Вторник,Среда,Четверг,Пятница,Суббота,Воскресенье"); КонецЦикла; ТекущиеДанные.ОбщееВремяСозданий = ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоЗамера; КонецПроцедуры
Здесь стоит пояснить, что можно было реализовать без повторяющегося кода. Однако, в данной реализации всё сделано специально, чтобы было как можно меньше сомнений в одинаковых условиях выполнения методов. Пусть лучше мы сделаем не такой классный и красивый код, как хотелось бы, зато получим более точные результаты.
Ну всё. Инструмент готов!
Сравнение
Пробуем запустить замеры на серверной базе. Для этого поочередно каждый метод в цикле создаёт по N раз одну и ту же коллекцию из заранее известных элементов. И так указанное количество «подходов».
Почему одну и туже? Потому что в этом и суть эксперимента — показать, как будут работать такие создания, если вы где-то в коде захотите быстро создать наполненную заранее известными значениями коллекцию. И как будут работать примеры типовых, указанные выше.
Для начала установим:
- Количество созданий в одном подходе: 10 000
- Количество подходов: 10
И глянем, насколько по скорости отличаются СтрРазделить() и РазложитьСтрокуВМассивПодстрок().
Код создания:
РезультатСоздания = СтрРазделить("Понедельник,Вторник,Среда,Четверг,Пятница,Суббота,Воскресенье", ",");
РезультатСоздания = РазложитьСтрокуВМассивПодстрок("Понедельник,Вторник,Среда,Четверг,Пятница,Суббота,Воскресенье", ",");
Результат неудивителен. Количество создания коллекции за одну миллисекунду у СтрРазделить() значительно выше:
Было 10 подходов. В каждый подход коллекция создавалась по 10 000 раз. В каждый подход количество создаваемых элементов (10 000) делились на общее затраченное время на их создание.
График построен на результатах, выраженных в этой таблице:
Спойлер
Метод |
Текущий подход |
Количество созданий |
Количество созданий за милисекунду |
Общее время созданий |
РазложитьСтрокуВМассивПодстрок() |
1 |
10 000 |
11,85 |
844 |
СтрРазделить() |
1 |
10 000 |
128,21 |
78 |
РазложитьСтрокуВМассивПодстрок() |
2 |
10 000 |
13,33 |
750 |
СтрРазделить() |
2 |
10 000 |
161,29 |
62 |
РазложитьСтрокуВМассивПодстрок() |
3 |
10 000 |
12,30 |
813 |
СтрРазделить() |
3 |
10 000 |
161,29 |
62 |
РазложитьСтрокуВМассивПодстрок() |
4 |
10 000 |
10,66 |
938 |
СтрРазделить() |
4 |
10 000 |
161,29 |
62 |
РазложитьСтрокуВМассивПодстрок() |
5 |
10 000 |
12,79 |
782 |
СтрРазделить() |
5 |
10 000 |
161,29 |
62 |
РазложитьСтрокуВМассивПодстрок() |
6 |
10 000 |
13,33 |
750 |
СтрРазделить() |
6 |
10 000 |
128,21 |
78 |
РазложитьСтрокуВМассивПодстрок() |
7 |
10 000 |
13,33 |
750 |
СтрРазделить() |
7 |
10 000 |
158,73 |
63 |
РазложитьСтрокуВМассивПодстрок() |
8 |
10 000 |
12,80 |
781 |
СтрРазделить() |
8 |
10 000 |
128,21 |
78 |
РазложитьСтрокуВМассивПодстрок() |
9 |
10 000 |
11,43 |
875 |
СтрРазделить() |
9 |
10 000 |
158,73 |
63 |
РазложитьСтрокуВМассивПодстрок() |
10 |
10 000 |
12,80 |
781 |
СтрРазделить() |
10 |
10 000 |
128,21 |
78 |
В принципе, не удивительно. Метод СтрРазделить() был специально оптимизирован так, чтобы заменить БСПшный РазложитьСтрокуВМассивПодстрок().
Ещё раз напомним, что методы не полностью идентичные и об этом писалось в статье Чем расщепить или "СтрРазделить() VS РазложитьСтрокуВМассивПодстрок()" ?
В рамках наших примеров, эти отличия не актуальны, однако ознакомится стоит.
Выходит, РазложитьСтрокуВМассивПодстрок() для подобного использовать не оптимально (интересно, почему в типовых до сих пор встречаются примеры). Но что покажет сравнение между СтрРазделить() и Новый Структура() ? Добавим в сравнение и этот метод:
РезультатСоздания = Новый Структура("Понедельник,Вторник,Среда,Четверг,Пятница,Суббота,Воскресенье");
Результаты замеров получились такие (спойлер)
Метод |
Текущий подход |
Количество созданий |
Количество созданий за милисекунду |
Общее время созданий |
Новый Структура() |
1 |
10 000 |
91,74 |
109 |
РазложитьСтрокуВМассивПодстрок() |
1 |
10 000 |
13,33 |
750 |
СтрРазделить() |
1 |
10 000 |
158,73 |
63 |
Новый Структура() |
2 |
10 000 |
91,74 |
109 |
РазложитьСтрокуВМассивПодстрок() |
2 |
10 000 |
13,33 |
750 |
СтрРазделить() |
2 |
10 000 |
161,29 |
62 |
Новый Структура() |
3 |
10 000 |
106,38 |
94 |
РазложитьСтрокуВМассивПодстрок() |
3 |
10 000 |
13,05 |
766 |
СтрРазделить() |
3 |
10 000 |
161,29 |
62 |
Новый Структура() |
4 |
10 000 |
106,38 |
94 |
РазложитьСтрокуВМассивПодстрок() |
4 |
10 000 |
12,80 |
781 |
СтрРазделить() |
4 |
10 000 |
158,73 |
63 |
Новый Структура() |
5 |
10 000 |
106,38 |
94 |
РазложитьСтрокуВМассивПодстрок() |
5 |
10 000 |
13,07 |
765 |
СтрРазделить() |
5 |
10 000 |
158,73 |
63 |
Новый Структура() |
6 |
10 000 |
106,38 |
94 |
РазложитьСтрокуВМассивПодстрок() |
6 |
10 000 |
13,33 |
750 |
СтрРазделить() |
6 |
10 000 |
128,21 |
78 |
Новый Структура() |
7 |
10 000 |
107,53 |
93 |
РазложитьСтрокуВМассивПодстрок() |
7 |
10 000 |
13,33 |
750 |
СтрРазделить() |
7 |
10 000 |
158,73 |
63 |
Новый Структура() |
8 |
10 000 |
91,74 |
109 |
РазложитьСтрокуВМассивПодстрок() |
8 |
10 000 |
13,33 |
750 |
СтрРазделить() |
8 |
10 000 |
158,73 |
63 |
Новый Структура() |
9 |
10 000 |
106,38 |
94 |
РазложитьСтрокуВМассивПодстрок() |
9 |
10 000 |
13,07 |
765 |
СтрРазделить() |
9 |
10 000 |
158,73 |
63 |
Новый Структура() |
10 |
10 000 |
106,38 |
94 |
РазложитьСтрокуВМассивПодстрок() |
10 |
10 000 |
12,32 |
812 |
СтрРазделить() |
10 |
10 000 |
158,73 |
63 |
Ну и, собственно, график (обожаю их):
И так, на графике видно, помимо того, что сервер периодически «проседает», и то, что СтрРазделить() лидирует в этом сравнении.
Даже в «худшие времена» СтрРазделить() срабатывает быстрее, чем Новый Структура() в лучшие.
Почему так?
Мы можем лишь предположить, что структура — это более затратная коллекция, чем массив. Насколько это верный вывод лучше уточнять у знатоков всея нутра платформы 1С.
И так, что имеем на данный момент? Вася, который утверждал, что для наших целей СтрРазделить() аки лучше, чем Новый Структура(), оказался прав. С точки зрения скорости этот метод будет работать быстрее. Естественно, что выигрыш в производительности на вряд ли позволит нам сказать, что пользователи будут прыгать от радости.
Вроде Вася уже собрался открывать бутылку шампанского, но тут подходит Он. Оптимальный Программист. Священник Восьми Платформ. Хранитель Желтых Талмудов и Свидетель Великого Ассемблера.
- Костыли всё это. Никаких созданий наполненного массива быть не должно! Зачем дополнительно напрягать вычислительную машину?
Новый Массив()
Эта статья нужна именно для того, чтобы сравнить между собой создания коллекций с заранее известными элементами. И Гуру программирования на нулях и единицах настаивает использовать только Новый Массив с последующими добавлениями элементов.
РезультатСоздания = Новый Массив; РезультатСоздания.Добавить("Понедельник"); РезультатСоздания.Добавить("Вторник"); РезультатСоздания.Добавить("Среда"); РезультатСоздания.Добавить("Четверг"); РезультатСоздания.Добавить("Пятница"); РезультатСоздания.Добавить("Суббота"); РезультатСоздания.Добавить("Воскресенье");
А что нам мешает сравнить?
Добавляем в наш отчёт и такой способ (спойлер)
Для этого в доработаем отчёт.
Функция ДанныеЗамеров(ПараметрыВыполнения) ДанныеЗамеров = Новый ТаблицаЗначений; //Просто заполним структуру таблицы из полей описанного нами набора схемы компоновки Для Каждого ТекущееПоле Из СхемаКомпоновкиДанных.НаборыДанных.Получить(0).Поля Цикл ДанныеЗамеров.Колонки.Добавить(ТекущееПоле.Поле, ТекущееПоле.ТипЗначения, ТекущееПоле.Заголовок); КонецЦикла; Если НЕ ЗначениеЗаполнено(ПараметрыВыполнения.Методы) Тогда Возврат ДанныеЗамеров; КонецЕсли; Для ТекущийПодход = 1 По ПараметрыВыполнения.КоличествоПодходов Цикл Для Каждого ТекущийМетод Из ПараметрыВыполнения.Методы Цикл ТекущиеДанные = ДанныеЗамеров.Добавить(); ТекущиеДанные.Метод = ТекущийМетод.Значение; ТекущиеДанные.ТекущийПодход = ТекущийПодход; ТекущиеДанные.КоличествоСозданий = ПараметрыВыполнения.КоличествоСозданий; Если ТекущиеДанные.Метод = "СтрРазделить" Тогда ЗамеритьМетодСтрРазделить(ТекущиеДанные); ИначеЕсли ТекущиеДанные.Метод = "НовыйСтруктура" Тогда ЗамеритьМетодНовыйСтруктура(ТекущиеДанные); ИначеЕсли ТекущиеДанные.Метод = "РазложитьСтрокуВМассивПодстрок" Тогда ЗамеритьМетодРазложитьСтрокуВМассивПодстрок(ТекущиеДанные); ИначеЕсли ТекущиеДанные.Метод = "НовыйМассив" Тогда ЗамеритьМетодНовыйМассив(ТекущиеДанные); КонецЕсли; Если ТекущиеДанные.ОбщееВремяСозданий > 0 Тогда ТекущиеДанные.КоличествоСозданийЗаМилисекунду = Окр(ТекущиеДанные.КоличествоСозданий / ТекущиеДанные.ОбщееВремяСозданий, 2); Иначе ТекущиеДанные.КоличествоСозданийЗаМилисекунду = ТекущиеДанные.КоличествоСозданий; КонецЕсли; КонецЦикла; КонецЦикла; Возврат ДанныеЗамеров; КонецФункции
Процедура ЗамеритьМетодНовыйМассив(ТекущиеДанные) НачалоЗамера = ТекущаяУниверсальнаяДатаВМиллисекундах(); Для ТекущееСоздание = 1 По ТекущиеДанные.КоличествоСозданий Цикл РезультатСоздания = Новый Массив; РезультатСоздания.Добавить("Понедельник"); РезультатСоздания.Добавить("Вторник"); РезультатСоздания.Добавить("Среда"); РезультатСоздания.Добавить("Четверг"); РезультатСоздания.Добавить("Пятница"); РезультатСоздания.Добавить("Суббота"); РезультатСоздания.Добавить("Воскресенье"); КонецЦикла; ТекущиеДанные.ОбщееВремяСозданий = ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоЗамера; КонецПроцедуры
И так. Принцип анализа тот же. Только теперь будем сравнивать четыре метода. Без особого желания, ведь победитель ясен. Создать и наполнить массив таки лучше, чем парсить строку и разбивать её на элементы...
Результат нас удивил.
Мы перепроверили. На разных серверах.
Под спойлером данные замеров
Метод |
Текущий подход |
Количество созданий |
Количество созданий за милисекунду |
Общее время созданий |
Новый Массив() |
1 |
10 000 |
80,00 |
125,00 |
Новый Структура() |
1 |
10 000 |
106,38 |
94,00 |
РазложитьСтрокуВМассивПодстрок() |
1 |
10 000 |
12,79 |
782,00 |
СтрРазделить() |
1 |
10 000 |
161,29 |
62,00 |
Новый Массив() |
2 |
10 000 |
80,00 |
125,00 |
Новый Структура() |
2 |
10 000 |
106,38 |
94,00 |
РазложитьСтрокуВМассивПодстрок() |
2 |
10 000 |
13,07 |
765,00 |
СтрРазделить() |
2 |
10 000 |
158,73 |
63,00 |
Новый Массив() |
3 |
10 000 |
80,00 |
125,00 |
Новый Структура() |
3 |
10 000 |
106,38 |
94,00 |
РазложитьСтрокуВМассивПодстрок() |
3 |
10 000 |
13,07 |
765,00 |
СтрРазделить() |
3 |
10 000 |
158,73 |
63,00 |
Новый Массив() |
4 |
10 000 |
91,74 |
109,00 |
Новый Структура() |
4 |
10 000 |
90,91 |
110,00 |
РазложитьСтрокуВМассивПодстрок() |
4 |
10 000 |
9,28 |
1 078,00 |
СтрРазделить() |
4 |
10 000 |
161,29 |
62,00 |
Новый Массив() |
5 |
10 000 |
90,91 |
110,00 |
Новый Структура() |
5 |
10 000 |
107,53 |
93,00 |
РазложитьСтрокуВМассивПодстрок() |
5 |
10 000 |
13,05 |
766,00 |
СтрРазделить() |
5 |
10 000 |
161,29 |
62,00 |
Новый Массив() |
6 |
10 000 |
80,00 |
125,00 |
Новый Структура() |
6 |
10 000 |
106,38 |
94,00 |
РазложитьСтрокуВМассивПодстрок() |
6 |
10 000 |
13,05 |
766,00 |
СтрРазделить() |
6 |
10 000 |
161,29 |
62,00 |
Новый Массив() |
7 |
10 000 |
90,91 |
110,00 |
Новый Структура() |
7 |
10 000 |
106,38 |
94,00 |
РазложитьСтрокуВМассивПодстрок() |
7 |
10 000 |
13,07 |
765,00 |
СтрРазделить() |
7 |
10 000 |
158,73 |
63,00 |
Новый Массив() |
8 |
10 000 |
80,00 |
125,00 |
Новый Структура() |
8 |
10 000 |
107,53 |
93,00 |
РазложитьСтрокуВМассивПодстрок() |
8 |
10 000 |
12,55 |
797,00 |
СтрРазделить() |
8 |
10 000 |
158,73 |
63,00 |
Новый Массив() |
9 |
10 000 |
91,74 |
109,00 |
Новый Структура() |
9 |
10 000 |
90,91 |
110,00 |
РазложитьСтрокуВМассивПодстрок() |
9 |
10 000 |
13,33 |
750,00 |
СтрРазделить() |
9 |
10 000 |
161,29 |
62,00 |
Новый Массив() |
10 |
10 000 |
80,00 |
125,00 |
Новый Структура() |
10 |
10 000 |
106,38 |
94,00 |
РазложитьСтрокуВМассивПодстрок() |
10 |
10 000 |
13,07 |
765,00 |
СтрРазделить() |
10 |
10 000 |
158,73 |
63,00 |
Оказывается, что СтрРазделить() быстрее, чем Новый Массив(). Более того, Новый Массив() ещё и борется за третье место с Новый Структура().
На создание и наполнение массива уходит больше времени, чем на парсинг строки при помощи СтрРазделить().
Пока мы удивлялись происходящему, к нам подплыл на волнах торсионных полей эзотерик от мира программирования Инокентий.
- Я знаю как вам помочь.
Продолжение следует...
В данной статье мы рассмотрели основные способы создания коллекции с заранее известными строковыми значениями. Примеры их использования есть и в типовых и, тем более, в всякого рода самописок и самодописок. По результатам замера вы сами можете сделать вывод. Разница есть, но не существенная. Какой подход использовать? Решать вам. Однако, на мой сугубо личный взляд, СтрРазделить выглядит более лаконично. Так что, если вы как-нибудь задумаетесь, мол, «этот массив из трех строк будет создаваться 100500 раз» , то не переживайте — написав его обычным созданием массива вы вряд ли предотвратите образование узкого места будущего кода.
В следующей статье разберем более «эзотерические» методы создания наполненного массива. И сравним их результаты.
Понравилась статья?
Не будьте равнодушными! Поставьте лайк звездочку и переходите к другим работам автора:
-
Не провоцируйте СКД, или пример "как не надо"
-
Сортируем ДанныеФормыДерево на клиенте
-
Менеджер открытых форм