gifts2017

Варианты конкатенации строк в 1С и замеры производительности.

Опубликовал Дмитрий К. (Dementor) в раздел Программирование - Практика программирования

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

Во встроенном языке платформы 1С:Предприятие, как и во многих других языках программирования, присутствует возможность сложения строк. Это легко:

Переменная="Мама"+"мыла"+"Раму";

Когда же нужно из некоторой коллекции строк получить одну единую, то можно сделать в цикле:

Строка = Строка + ЭлементКоллекции;

Все это хорошо работает когда у нас немного данных. Но все кардинально меняется, когда счет строк идет на тысячи (обычное дело при работе с клиент-банками, веб-сервисами, КПК и в прочих ситуациях). Попробуйте и сами увидите как на глазах падает производительность. О резкой деградацию производительности при множественных конкатенациях уже писали. Даже на Инфостарте. Не говоря уже про обсуждения на партнерском форуме.

Но водь нас больше всего интересуют практические решения. Варианты с внешними компонентами я даже не стал рассматривать. Нужно ведь писать код сразу так, что бы он работал кросплатформенно! Так же были проигнорированы варианты с записью в файл - нам лишние задержки от дисковой подсистемы совсем не нужны.

Некоторые предлагают очевидное в таком случае решение - использование текстового документа. С практической стороны необходимо отметить, что все составные строки в этом объекте идут отдельными строками. Т.е. воспользовавшись методом ПолучитьТекст() необходимо еще сделать замену переносов строк на пустую строку. В случае использования вами символа переноса строки в подстроках, необходимо предварительно сделать замену его на некоторую уникальную последовательность символов, а после получения результата произвести обратное преобразование.

Я же для себя изобрел собственный велосипед, который по скорости превзошел использование текстового документа. Все подстроки заносятся в массив, который перегоняется в текстовое представление с помощью ЗначениеВСтрокуВнутр(), а далее вычищается от "лишнего". Работает стабильно и довольно быстро. Подробности реализации можете посмотреть в прикрепленной обработке.

UPD 1. Из комментария узнал про новый способ конкатенирования - использование объекта ЗаписьXML. У него есть интересный метод ЗаписатьБезОбработки() для помещения уже готового документа в том виде, какой подается на вход, т.е. без лишних тегов.

Для того, что бы определить какой метод лучше (и стоило ли вообще заморачиваться) была написана маленькая обработка. Условия для всех равны - замер происходит в милисекундах от вызова серверной функции с реализацией соответствующего алгоритма до получения отклика. Что бы нивелировать случайные факторы, я проводил по четыре замера и выводил в таблицу среднее значение.

В результате я получил следующую таблицу:

 

Попыток Обычная конкатенация Текстовым документом Масивом подстрок
1000

63

97 57
5000

327

353 185
10000

847

642 330
15000

4100

958 462
20000

8672

1299 656

В результате мы еще раз убедились в непрактичности использования обычной конкатенации на больших объемах строк. Как видно из получившегося графика зависимость скорости выполнения от количества элементов имеет экспоненциальный характер. В то время, как оба метода "обхода" стабильно показывают прямолинейную зависимость. Что позволяет нам прогнозировать общее время выполнения обработок связанных с обработкой текста. И мой метод превосходит по быстродействию использование текстового документа в 2 разаCool

UPD 2. К сожалению не нашел в инфостартовском редакторе инструмента для редактирования количества столбцов таблицы и не увидел переключения в режим HTML-документа для правки руками. По результатам тестирования метода с ЗаписьXML получились результаты идентичные методу массивом как на малых, так и на больших наборах подстрок. Поэтому я отдаю этому методы лавры победителя - при прочих равных он легко запоминается и не содержит подводных камней.

Скачать файлы

Наименование Файл Версия Размер
Тестирование вариантов конкатенации 10
.epf 6,59Kb
13.06.14
10
.epf 1 6,59Kb Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Сергей (ildarovich) 13.06.14 06:11
Странно, но в статье Опять двойка, на которую автор ссылается, уже приводился предлагаемый здесь метод. Даже код уже был приведен
Функция ВСтроку(Массив) Экспорт
    Возврат Сред(СтрЗаменить(ЗначениеВСтрокуВнутр(Массив), """}," + Символы.ПС + "{""S"",""", ""), 53 + СтрДлина(Формат(Массив.Количество(), "ЧГ=")), Массив.Количество())
КонецФункции

Также в комментарии http://forum.infostart.ru/forum24/topic75023/message908183/#message908183 к той статье приведен еще более быстрый (на 12%) метод за авторством speshuric с использованием объекта ЗаписьXML.
2. Дмитрий К. (Dementor) 13.06.14 12:10
(1) ildarovich, все возможно. Но финт со ЗначениеВСтрокуВнутр() я придумал для своей обработки работы с веб-сервисом, которая до этого очень медленно работала. После этого я решил сравнить её быстродействие с "классикой" и способом, который нашел на партнерском форуме. А уже затем я решил поделится с общественностью своей наработкой. Про статью "Опять двойка" узнал в процессе верстки своей, так же как и про другие отдаленно похожие заметки (на других ресурсах). От мысли писать свою статью я не отказывался по причинам: она оригинальная, не повторяет чужих идей, приведены конкретные цифры замеров производительности в то время, когда другие лишь мимолетом упоминали про свои субъективные ощущения.

Раз существует более "навороченный" вариант с ЗаписьXML, то конечно стоит его рассмотреть и добавить в табличку сравнения быстродействия. Я думал и про этот объект, но не знал про его любопытный метод ЗаписатьБезОбработки() и потому не стал рассматривать. А вот от использования указанной в комменте реализации составления строки из массива я бы рекомендовал воздержаться - в ней есть баг, который я у себя дополнительно обошел (хотя в некоторых случаях искажение содержимого роли не играет и потому некоторым может подойти).
ildarovich; +1 Ответить
3. Дмитрий К. (Dementor) 13.06.14 14:40
(1) ildarovich, про 12% - полное вранье. Добавил в обработку тестирование ЗаписиXML - результаты сопоставимы с методом массива почти на 99%!!! Так на формирование строки из 50000 подстрок методом массива уходит 1466 милисекунда, а с помощью ЗаписиXML - 1474. При работе со 100000 подстрок результаты - 2906 и 2985. Единственное преимущество - элегантность кода и отсутствие шаманства.
4. Дмитрий К. (Dementor) 13.06.14 15:07
Статья и обработка обновлены четвертым способом конкатенирования строк.
5. Пользователь Инфостарта (infostart user) 19.08.14 13:08
6. Дмитрий К. (Dementor) 19.08.14 13:55
(5) infostart user, это не способ, а всего лишь анонс будущей функциональности. Как показывает практика, самый короткий промежуток между заметкой в зазеркалье и получением тестовой сборки платформы равен полугоду. Скорее всего добавят в 8.3.6
7. Улугбек Джамшудов (Улугбек) 19.08.14 13:26
Как говорится - в 8-ке это реализовано:

http://v8.1c.ru/o7/201408str/index.htm

Функция форматирования СтрШаблон()
Функция работы со строками СтрСравнить()
Функции работы со строками СтрНачинаетсяС(), СтрЗаканчиваетсяНа()
Функции работы со строками СтрРазделить(), СтрСоединить()
Функция работы со строками СтрНайти()
8. Дмитрий К. (Dementor) 19.08.14 15:03
(7) Улугбек, а на заборе написано, что Цой жив. И еще много чего тоже написано...
А попробуйте зайти в конфигуратор и воспользоваться этими функциями!

Подсказка: в ЗАЗЕРКАЛЬЕ пишут разработчики платформы о новых фичах, которые они у себя разрабатывают. Это не место для официальных пресс-релизов, а всего лишь блог. После разработки пройдет еще цикл тестирования и по результатам примут решение, когда переносить их в рабочие сборки.
9. Улугбек Джамшудов (Улугбек) 19.08.14 14:07
10. Сергей (Che) Коцюра (CheBurator) 20.08.14 18:15
После разработки пройдет еще цикл тестирования и по результатам примут решение, когда переносить их в рабочие сборки.

вау, там у них есть тестирование? мы перестанем чувстовать себя подопытными кроликами? наконец-то!
11. Дмитрий К. (Dementor) 20.08.14 19:58
(10) CheBurator, разве можно быть настолько доверчивым?
Людям свойственно ошибаться, даже при тестировании на наличие ошибок :)
12. Анатолий Мощенко (with) 20.08.14 21:00
ИМХО
1) 1С генерирует не исполняемый код, в всего лишь строит объектную модель, которая потом исполняется в виртуальной машине.
2) Такие типы интерпретаторов не предназначены для большого количества вычислений, которые требуют скорости работы. Написанный код на 1С всегда уступит по скорости реализации на с++. Это надо понимать, и не ждать чудес.
Ну и последнее, приведенные примеры работают быстрее, потому что там строки создаются и обрабатываются на уровне одного объекта, написанного на с++ и 1С там только дергает системные ф-ции.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа