|   |   | 
| 
 | Медленное сложение строк | ☑ | ||
|---|---|---|---|---|
| 0
    
        PitNN 24.08.16✎ 12:07 | 
        Добрый день, коллеги.
 Возникла непонятная ситуация. Сложение строк на тороне сервера происходит очень долго. Конкретно: Стр = стр + "('" + СтрокаСоотношения.ГУИД + "', '"; Данная операция выполнившись 152899 раз заняла 72,663834 секунды и находится на первом месте в замере производительности. Вторая в списке тяжелых конструкций: Стр = стр + "', '" + ИДПрайса + "')"; Соответственно 152899 раз и 72,093324 секунд. Данное с Отдельное тестирование сложений тысячи строк из ста символов выдает что данная операция делается меньше секунды. С чем может быть связано подобное поведение? | |||
| 1
    
        Lexey_ 24.08.16✎ 12:08 | 
        (0) с обращением через точку     | |||
| 2
    
        Nuobu 24.08.16✎ 12:09 | 
        С преобразованием типов.     | |||
| 3
    
        PitNN 24.08.16✎ 12:11 | 
        (1) Не согласуется с второй строкой, когда обращения через точку отсутствует     | |||
| 4
    
        PitNN 24.08.16✎ 12:12 | 
        (2) ИДПрайса Изначально имеет тип "Строка"     | |||
| 5
    
        Nuobu 24.08.16✎ 12:12 | 
        Отдельное тестирование сложений тысячи строк из ста символов выдает что данная операция делается меньше секунды. 
 А теперь "меньше секунды" умножь на 152. Ибо ты тестировал тысячу, а у тебя - 152 000. | |||
| 6
    
        hitodom 24.08.16✎ 12:14 | 
        сложение строк не сильная сторона 1с. попробуй записьтекста     | |||
| 7
    
        PitNN 24.08.16✎ 12:15 | 
        (5) Неправильно написал, виноват. Там идет цикл 150000 раз.
 Собирается строка из строк по сто символов. На каждой тысячной итерации строка обнуляется. Вот это полное действие делается меньше секунды | |||
| 8
    
        WebberNSK 24.08.16✎ 12:16 | 
        (0) http://speshuric.livejournal.com/163665.html
 рекомендую почитать | |||
| 9
    
        PitNN 24.08.16✎ 12:20 | 
        Вот часть кода:
 ТекДатаВремя = Формат(ТекущаяДата(),"ДФ=yyyy-MM-dd")+" "+Формат(ТекущаяДата(),"ДФ=ЧЧ:мм:сс"); Ошибка = ""; НужнаЗапятая = Ложь; сч = 0; стр = "INSERT INTO c_lees (`guid`, `partner`, `guidsupplier`, `daysdelivery`, `guidstorage`, `quantity`, `date`, `id_price_list`) VALUES "; Поставщик = Соглашение.Контрагент.Наименование; ПоставщикГУИД = Соглашение.Контрагент.ГУИД; ДнейДоставки = 0; СкладГУИД = "e73df8ac-f2f8-11e4-8673-3085a93da151"; Если Поставщик <> "трам-там-там" Тогда ДнейДоставки = Строка(Соглашение.СрокПоставки); СкладГУИД = "ad412042-3eeb-11e3-a566-001e6707b110"; КонецЕсли; Для каждого ВыборкаОстатков Из ИзмененныеПозиции Цикл Если НужнаЗапятая Тогда Стр = Стр + ","; КонецЕсли; Стр = стр + "('"+ВыборкаОстатков.НоменклатураГУИД; Стр = стр + "', '"+Поставщик + "', '"; Стр = стр + ПоставщикГУИД + "', '"; Стр = стр + ДнейДоставки + "', '"; Стр = стр + СкладГУИД + "', '"; Стр = стр + ?(ВыборкаОстатков.ВНаличии < 0.5, Окр(ВыборкаОстатков.ВНаличии), Формат(Окр(ВыборкаОстатков.ВНаличии), "ЧГ=0")); Стр = стр + "', '" + ТекДатаВремя + "', '"; Стр = стр + ИДПрайса + "')"; сч = сч+1; Если сч >= 1000 Тогда сч = 0; стр = "INSERT INTO c_lees (`guid`, `partner`, `guidsupplier`, `daysdelivery`, `guidstorage`, `quantity`, `date`, `id_price_list`) VALUES "; НужнаЗапятая = Ложь; КонецЕсли; КонецЦикла; Как видно переменная ТекДатаВремя изначально имеет тип строка, но при этом Стр = стр + "', '" + ТекДатаВремя + "', '"; выполнившись 50000 раз затратило 29,4 секунд. Это к вопросу о приведении типов | |||
| 10
    
        PitNN 24.08.16✎ 12:22 | 
        (8) Спасибо, изучаю     | |||
| 11
    
        Serginio1 24.08.16✎ 12:22 | 
        Используй ЗаписьXML.ЗаписатьБезОбработки(стр); 
 Пример можно посмотреть здесь http://catalog.mista.ru/public/544232/ | |||
| 12
    
        Fragster гуру 24.08.16✎ 12:23 | 
        (11) прав.     | |||
| 13
    
        hitodom 24.08.16✎ 12:23 | 
        А просто ЗаписьТекста хуже?     | |||
| 14
    
        ptiz 24.08.16✎ 12:24 | 
        (0) Чем больше строка - тем дольше добавление.     | |||
| 15
    
        ptiz 24.08.16✎ 12:28 | 
        ЗаписьТекста (добавление без перевода строки) + ЧтениеТекста поможет     | |||
| 16
    
        Мыш 24.08.16✎ 12:35 | 
        Стр = Стр + "текст";
 Особенности работы с памятью. Область памяти под переменную динамически увеличивается. Накладные расходы на эту операцию составляют основное время, имхо. | |||
| 17
    
        Fragster гуру 24.08.16✎ 12:36 | 
        (13) вроде она через память не работает, а только через файл     | |||
| 18
    
        Jija Grenkov 24.08.16✎ 12:41 | 
        (16) скорее всего нечего не увеличивается. Просто стр и "текст" теряют ссылки и уходят в муссор, а под новую итоговую строку выделятся нужный объем памяти. И так очень много раз. От чего сборщик муссора пыхтит. Скорее всего и процесс отъедает ядро проца полностью     | |||
| 19
    
        Мыш 24.08.16✎ 12:42 | 
        (18) Тоже вариант. Точно только у разработчиков платформы узнать можно )     | |||
| 20
    
        Fragster гуру 24.08.16✎ 12:43 | 
        (18) стр = стр + стр в цикле очень быстро сжирает память, так как ищет непрерывный кусок для результата, даже сборщик мусора не помогает. ну и тормозит.     | |||
| 21
    
        apokrit 24.08.16✎ 12:47 | 
        (0) Если версия платформы + режим совместимости позволяют, можно использовать СтрСоединить. Метод специально для этого и делали.     | |||
| 22
    
        Serginio1 24.08.16✎ 12:53 | 
        (13) Здесь есть сравнение
 http://speshuric.livejournal.com/163665.html | |||
| 23
    
        DrZombi гуру 24.08.16✎ 12:59 | 
        (22) Какая любопытненькая статейка :)     | |||
| 24
    
        Мыш 24.08.16✎ 13:17 | 
        (21) Сравнил, кстати. ЗаписьXML и СтрСоединить() сравнимы по скорости )     | |||
| 25
    
        PitNN 24.08.16✎ 15:45 | 
        (11) Да, действительно, на первое место вылезли уже другие операции. Огромное спасибо) Как говорится век живи - век учись)     | |||
| 26
    
        PitNN 24.08.16✎ 15:50 | 
        Подскажите еще, пожалуйста. Что эффективнее, выполнение одной большой инструкции Соединение.Execute(ТекстЗапросовInsert);
 или нескольких поменьше? | |||
| 27
    
        Fragster гуру 24.08.16✎ 16:01 | 
        (26) есть нюансы     | |||
| 28
    
        Fragster гуру 24.08.16✎ 16:02 | 
        можно вообще отправить большой инсерт асинхронно и дальше работать     | |||
| 29
    
        PitNN 24.08.16✎ 16:08 | 
        (27) Что за нюансы, подскажи пожалуйста     | |||
| 30
    
        PitNN 24.08.16✎ 16:09 | 
        (28) Как это выглядит?     | |||
| 31
    
        orefkov 24.08.16✎ 16:41 | 
        Сборщик мусора в 1С? Отличные грибы!     | |||
| 32
    
        b_ru 24.08.16✎ 16:45 | 
        (31) А что, в 1С его нету?     | |||
| 33
    
        Смотрящий 24.08.16✎ 16:46 | 
        (30) Для начала покупаешь IIS     | |||
| 34
    
        orefkov 24.08.16✎ 16:50 | 
        (32)
 Нет конечно. Только счётчик ссылок в каждом объекте. Память освобождается сразу при освобождении объекта. Циклические ссылки висят до смерти процесса. | |||
| 35
    
        aka AMIGO 24.08.16✎ 17:02 | 
        (34) Кто/Что заботится об очистке памяти? 1С? или всё-таки ОСь?     | |||
| 36
    
        b_ru 24.08.16✎ 17:04 | 
        (34) Мне почему-то казалось, что это простейшая реализация сборки мусора, но да, по формальному определению оно ей не является :(     | |||
| 37
    
        PitNN 24.08.16✎ 18:14 | 
        Сделал отправку одного большого запроса на сервер. Стало быстрее чем несколько меньших     | |||
| 38
    
        Jija Grenkov 24.08.16✎ 21:47 | 
        (34) получается и на сервере такой подход? Тогда понятно откуда неизбежные утечки памяти. Еще скорее всего нет никаких механизмов дефрагментации памяти так как этим обычно занимается GC 
 (36) По идее это было GC, если бы запускалось в отдельном процессе, а тут видимо interceptor в тех местах где пропадает ссылка. На сколько помню в objective C похожий подход. | |||
| 39
    
        Torquader 24.08.16✎ 22:02 | 
        (38) Это не сборка мусора, а процесс управления кучей памяти.
 Он ничего никуда не перемещает, а просто или выделяет память или освобождает. Что же касается строк, то упирается всё не в выделение памяти, а в копирование предыдущего значения строки, в новое место. Причём, со сложением строк в javascript те же "тапки" - тормозит так, что хочется в экран плюнуть. | |||
| 40
    
        Jija Grenkov 24.08.16✎ 22:18 | 
        (39) почти везде так будет где строки иммутабельны. К примеру в джаве есть мутабельная и иммутабельная строка.     | |||
| 41
    
        Jija Grenkov 24.08.16✎ 22:25 | 
        (39) в JS можно использовать массив, должно быть быстрее     | |||
| 42
    
        Torquader 24.08.16✎ 22:54 | 
        Проблема в том, что когда складываешь две строки, нужно, чтобы под результат была выделена память - и в момент выделения памяти потребуется перенести блок данных из одного места в другое - всё равно будет memcpy только уже на уровне выделения памяти.     | |||
| 43
    
        Jija Grenkov 25.08.16✎ 00:08 | 
        (42) не все так однозначо. Когда мы в цикле складываем 2 переменных типа строка и присваиваем - это значение 1-й переменной,
 for (var i=0; i<10000; i++){ Var a += "foo"; } то выделяется область под результирующую строку куда копируються данные 2-х строк источников и так много раз. И GC тратит ресурс на освобождение памяти от 2-х исходных строк. Когда используется буфер, то в нем заранее выделена память под всю результирующую строку. В случае с JS некое подобие работы с буфером это создать массив где лежать все кусочки строки и 1 операцией сцепить все строки. В таком случае интерпритатору очень просто определить размер результирующей строки. var arr = [] for (var i=0; i<10000; i++){ arr.push("foo"); } arr.join("") ps. Сейчас браузеры пытаются оптимизировать 1й вариант и не везде получится увидеть разницу. | |||
| 44
    
        H A D G E H O G s 25.08.16✎ 00:50 | 
        (43) Сам то понял, что сказал?     | |||
| 45
    
        Jija Grenkov 25.08.16✎ 01:03 | 
        (44) естественно, если не ясно детальное объяснение, скажу короче. В 1 варианте операций выделения памяти и сборки мусора больше.     | |||
| 46
    
        Jija Grenkov 25.08.16✎ 01:17 | 
        1 вариант:
 - В каждой итерации выделится и станет "муссором" память под "foo". - Каждую итерацию будет выделена и станет "муссором" память под состояние переменной "а". Размер переменной "а" будет увеличиваться с каждой итерацией. 2 вариант: - В каждой итерации выделится память под "foo". - 1 раз после цикла выделится память под итоговую строку после чего память выделенная под "foo" станет "муссором" | |||
| 47
    
        H A D G E H O G s 25.08.16✎ 02:12 | 
        (46) Проблема очистки стоит в этих ваших виртуальных машинах. В наших православных Дельфи проблемы очистки нет. Есть проблемы утечки. Которую контролят спецутилиты на этапе разработки.
 Что до строк, то есть 3 стратегии конкатенации: 1) Реаллокация на каждый чих 2) Программер сам знает (знает только программер, менеджер памяти никогда этого не знает) какой длины у него результирующая строка. Он выделяет память сразу и пишет в нее. Простейший пример BASE64 с ее 4/3 размером. 3) Мудрый менеджер памяти/среда разработки выделяет память под строки блоками, байт по 8000, к примеру, как это делает TStream в Дельфи. Самый годный вариант, кстати. Но я бы буфер сделал бы больше, по 64 Кбайта норм. Это все, что нужно знать в этой теме. Все остальное - лишнее. | |||
| 48
    
        Jija Grenkov 25.08.16✎ 02:43 | 
        (47) Обджект паскаль может и  был не плохим языком, но факт остается фактом, что этот ЯП самоликвидировался и именно из за конкуренции с языками работающими на виртуальной машине(java, c#).
 В джаве нет таких проблем, там и оптимизатор умный и девелопер может использовать StringBuilder и сам указать capacity этого билдера/буфера. Есть область памяти называемая пулом стрингов, где строки могут кешироваться и при повторном использовании литерала память не будет выделяться (в примере для JS под "foo" память выделится 1 раз) В джава так же есть возможность напрямую управлять памятью и эта память будет не под управлением виртуальной машине, мы такое в бигдате юзаем. | |||
| 49
    
        Garykom гуру 25.08.16✎ 03:12 | 
        (48) Да удобство работы с динамическим выделением памяти в объектном паскале не очень по сравнению с Java/C#.
 Требует более высокого скилла прогов (как и C++), но конечный результат для пользователей чреват требованием апгрейда железа. | 
| Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |