Имя: Пароль:
1C
1С v8
Оценка производительности кода
0 temmy70
 
15.03.16
09:29
Добрый день, комрады. Интересную штуку заметил сегодня. В оценке производительности вижу 2 строчки:

СчетчикСимволов = СчетчикСимволов + 1;

и

Если МассивСпецСимволов.Найти(ТекущийСимвол) = Неопределено Тогда

Увеличение счетчика символов выполняется 0,000754 с, а поиск в массиве выполняется 0,000023 с. В массиве спецсимволов 9 элементов. Сами цифры малы конечно, но разница то между ними огромная, и при выполнении в цикле на 1000 итераций, сильно заметно. Платформа 8.3.7.1949, замеры проводил несколько раз, для статистики так сказать. Собсна вопрос, почему так то?
1 NcSteel
 
15.03.16
09:35
Разные операции и разное время выполнение, что не так?
2 НЕА123
 
15.03.16
09:37
имхо. плавающая арифметика.
3 temmy70
 
15.03.16
09:46
(1) о, и правда разные, не увидел сразу. ))
(2) выполняем большой цикл, чтобы усреднить показания. Цикл на 1200 итераций. результат у нас получается:
- добавление единички 0,35 секунды
- поиск в массиве 0,02 секунды.

Просто интересно, неужели добавление единички сложнее в 10 раз, чем поиск в массиве. Мож я единичку добавляю не так, может там с присвоением что-то.
4 floody
 
15.03.16
10:02
Не забывайте, что платформа чисто прикладная. Может быть всё, что угодно имхо.
5 Fragster
 
гуру
15.03.16
10:04
сделай счетчик символов реквизитом формы типа число
6 Fragster
 
гуру
15.03.16
10:05
ну и да - можно весь код?
7 vde69
 
15.03.16
10:05
переменная имеет тип - variant (от сюда не очень большая скорость)
а поиск в массиве оптимизирован...
8 temmy70
 
15.03.16
10:06
Тестируем дальше )))
Первый вариант:

...
СчетчикСимволов    = 0;
КоличествоИсходныхСимволов = СтрДлина(ТекстСМС);
Для инд = 1 по КоличествоИсходныхСимволов Цикл
    ТекущийСимвол = Сред(ТекстСМС, инд, 1);
    Если МассивСпецСимволов.Найти(ТекущийСимвол) = Неопределено Тогда
        СчетчикСимволов = СчетчикСимволов + 1;
    Иначе
        СчетчикСимволов = СчетчикСимволов + 2;
    КонецЕсли;
КонецЦикла;
...


Второй вариант:

...
СчетчикСимволов    = СтрДлина(ТекстСМС);
КоличествоИсходныхСимволов = СчетчикСимволов;
Для инд = 1 по КоличествоИсходныхСимволов Цикл
    ТекущийСимвол = Сред(ТекстСМС, инд, 1);
    Если не МассивСпецСимволов.Найти(ТекущийСимвол) = Неопределено Тогда
        СчетчикСимволов = СчетчикСимволов + 1;    
    КонецЕсли;
КонецЦикла;
...


Время выполнения:
1 - 0,51
2 - 0,19
9 vde69
 
15.03.16
10:07
ну и до кучи

все замеры точнее 0.001 сек - это вообще лажа
все замеры точнее 1/17 секунды - довольно приблизительны
10 temmy70
 
15.03.16
10:08
(9) согласен, поэтому делаю большое количество выполнений.
11 Рэйв
 
15.03.16
10:08
(0)Поиск реализован на вставке асм, а присвоение на чистом С++ или вроде того

Как вариант:-)
12 Господин ПЖ
 
15.03.16
10:09
нестрогая типизация сыграла с плейшнером злую шутку
13 sash-ml
 
15.03.16
10:10
(11)  близко. поиск в массиве нативный тоесть компилируется , прибавление к произвольной переменной интерпретируется.
14 Fragster
 
гуру
15.03.16
10:10
(8) что такое "счетчик выполнения?" да и вообще, мой телепат говорит, что найдя любой символ не из ascii надо останавливаться и умножать длину на два.
15 Fragster
 
гуру
15.03.16
10:10
потому что в sms не utf-8, а utf-16
16 Fragster
 
гуру
15.03.16
10:11
в таком случае
17 Fragster
 
гуру
15.03.16
10:11
в (14) "счетчик выполнения?" -> "время выполнения?"
18 Zhuravlik
 
15.03.16
10:11
имхо, массив оперирует данными которые уже закешированы в памяти, а счетчик инициализирует изменение своей переменной в буфере.
Я думаю если перед поиском элемента в массиве этот элемент туда вставлять (в смысле замерять еще и эту операцию) - разница будет существенна.
19 Fragster
 
гуру
15.03.16
10:12
и в данном случае надо организовывать не поиск по массиву,  проверку кода символа Сред(Текст, счетчикцикла, 1) на >127
20 temmy70
 
15.03.16
10:16
(19) ваш телепат вас подводит. Написано же, массив спецсимволов. Или вы думаете, что я туда весь алфавит запихал? В данном случае я просто проверяю наличие символов, которые всегда идут за 2, не зависимо от кодировки, например "{", "}", "[", "]". Да и спрашивал я совсем о другом.
21 temmy70
 
15.03.16
10:19
(17) время выполнения в секундах, из оценки производительности.
22 Timon1405
 
15.03.16
10:22
(20) если не трудно, озвучьте задачу полностью, нам же интересно.
23 Лефмихалыч
 
15.03.16
10:23
(0) замени массив на соответствие - офигеешь
24 f_vadim
 
15.03.16
10:25
как-то сложно... массив, соответствие

СтрНайти(Символ, "[]{}") > 0
25 Fragster
 
гуру
15.03.16
10:28
(20) понятно. ну, тогда см. (5)
26 los_hooliganos
 
15.03.16
10:29
Поиск в массиве реализован по сути перебором массива. Перепиши свой код, офигеешь от циферь.
27 temmy70
 
15.03.16
10:31
(22) задача посчитать, в сколько СМС выйдет отправка сообщения клиенту. Я посимвольно смотрю текст отправки. Если символ попадает в спецсимволы, то его считаем за 2 и тут же смотрим код символа, если хоть один попал выше 127 или символ = "€", то будет аскии.
Потом проверяем общее количество символов, если не превысили 70 или 160, то хорошо. Если превысили, то считаем количество СМС кратно 67 или 153. Как-то так.
28 temmy70
 
15.03.16
10:32
(25) что мне даст реквизит формы, и что делать, если формы нет?
29 NcSteel
 
15.03.16
10:33
(27) А не проще в строке заменить спец символы на "00" или что то в этом роде. А потом просто взять длину строки?
30 f_vadim
 
15.03.16
10:35
(28) у реквизита указывается его тип и, возможно, при инкременте не будет дополнительных плясок.

а вообще измерять производительность на подсчёте пары сотен символов это где-то рядом с котом, которому делать нечего.
31 NcSteel
 
15.03.16
10:36
(30) он вирус пишет, который должен к 1Ске присасываться и рассылать спам из 1С
32 Fragster
 
гуру
15.03.16
10:38
(28) если нет формы, значит есть объект обработки. если нет объекта обработки и это, допустим, фоновое задание, значит грустим :)
но такие задачи, когда все упирается именно в счетчик - очень редки. Да и оптимизируются они достаточно просто. например в данном случае можно увеличивать счетчик только в случае попадания в массив спецсимволов, а потом прибавлять длину.
33 temmy70
 
15.03.16
10:38
у меня вообще вопрос был в другом. ))) То что для меня всегда казалось простой операцией, добавить счетчику единичку, на деле оказалась "тяжелой". И для себя сейчас делаю вывод, что если возможность это избежать, ну или частично избежать, то это нужно делать.
34 Fragster
 
гуру
15.03.16
10:39
чаще на большом количестве соединений строк через + при работе с длинными строками проседает
35 NcSteel
 
15.03.16
10:39
(33) Глупый вывод.
36 Fragster
 
гуру
15.03.16
10:39
(33) не нужно.
37 temmy70
 
15.03.16
10:39
(32) вот это я в (8) и сделал ))
38 NcSteel
 
15.03.16
10:39
А вообще если код писать в одну строку, то производительность тоже возрастет, а надо ли?
39 Fragster
 
гуру
15.03.16
10:40
(38) она только в режиме отладки возрастет ;)
40 Карупян
 
15.03.16
10:41
Поиск в массиве происходит простым перебором, тк никаких индексов для массива не создается
41 temmy70
 
15.03.16
10:41
(35) (36) почему?
42 Карупян
 
15.03.16
10:42
(41) Делать математику на 1с глупо. На внешней компоненте можно получить прирост в несколько ПОРЯДКОВ
43 temmy70
 
15.03.16
10:43
(42) о какой математике идет речь, не совсем понял.
44 Fragster
 
гуру
15.03.16
10:44
(41) потому что один запрос к базе или, там, запись объекта, будет в тысячи раз дольше, чем инкремент, даже так реализованный. Соответственно, общая доля во времени выполнения кода будет пренебрежимо мала.
45 NcSteel
 
15.03.16
10:46
(39) )))) не раскрывай секреты
46 Fragster
 
гуру
15.03.16
10:46
а вот время доработки, когда надо будет через пол года что-то поменять, будет существенно меньше
47 temmy70
 
15.03.16
10:50
(46) это конечно да, соглашусь.
48 NcSteel
 
15.03.16
10:52
(47) Оптимизировать можно бесконечно, но надо руководствоваться соизмеримостью.
49 ДенисЧ
 
15.03.16
11:07
Никогда не забывайте, что
premature optimization is the root of all evil
50 Fragster
 
гуру
15.03.16
11:09
(49) не, "сначала делаем, потом думаем" и маркетологи - вот от чего всё горе.
51 ДенисЧ
 
15.03.16
11:12
(50) Ага,... "Фигак-фигак, и в продакшен"...
52 temmy70
 
15.03.16
11:14
(50), (51) маркетологи дааааа, из-за них так и выходит, фигак фигак и в продакшен, потому что все время так: "мы вчера придумали, завтра запускаем!"
53 ДенисЧ
 
15.03.16
11:14
(50) (52) Вот так взять и назвать гуру маркетологом...
Это сильно...
54 Кирпич
 
15.03.16
11:21
(0) "Собсна вопрос, почему так то?" потому что получилось.
Я не знаю как оно там внутри работает, но если оно работает так медленно, то скорее всего там у них какая нибудь дубовая стековая машина на вариантных переменных. Поиск массива выполняется скомпилированым машинным кодом, а сложение выполняется дубовым интерпретатором типа:

сунуть в стек СчетчикСимволов
сунуть в стек 1
сложить
высунуть из стека в СчетчикСимволов

и при каждой операции надо проверять типы операндов, увеличивать счетчики, следить за размером стека и тд. и тп.
55 Ildarovich
 
15.03.16
11:53
Думаю, самое простое объяснение тут - НЕПРАВИЛЬНЫЕ ЗАМЕРЫ. Вот что получилось у меня:
-------------------------
Циклов    1 000 000
Инкремент 0,000702 мсек
Поиск     0,001716 мсек
-------------------------
Для тестирования использовал такой код:
СчетчикСимволов = 0;
    
    МассивСпецСимволов = Новый Массив;
    
    МассивСпецСимволов.Добавить("{");
    МассивСпецСимволов.Добавить("}");
    МассивСпецСимволов.Добавить("[");
    МассивСпецСимволов.Добавить("]");
    МассивСпецСимволов.Добавить("{");
    МассивСпецСимволов.Добавить("}");
    МассивСпецСимволов.Добавить("[");
    МассивСпецСимволов.Добавить("]");
    МассивСпецСимволов.Добавить("{");
    
    Старт = ТочноеТекущееВремя();
    Для ё = 1 По ЧислоЦиклов Цикл
        СчетчикСимволов = СчетчикСимволов + 1;    
    КонецЦикла;
    Время1 = - Старт + ТочноеТекущееВремя();
    
    Старт = ТочноеТекущееВремя();
    Для ё = 1 По ЧислоЦиклов Цикл
    КонецЦикла;
    Время0 = - Старт + ТочноеТекущееВремя();
    
    ТекущийСимвол = "_";
    
    Старт = ТочноеТекущееВремя();
    Для ё = 1 По ЧислоЦиклов Цикл
        Если МассивСпецСимволов.Найти(ТекущийСимвол) = Неопределено Тогда
        КонецЕсли    
    КонецЦикла;
    Время2 = - Старт + ТочноеТекущееВремя();
    
    Сообщить("-------------------------");
    Сообщить("Циклов    " + ЧислоЦиклов);
    Сообщить("Инкремент " + (Время1 - Время0) / ЧислоЦиклов + " мсек");
    Сообщить("Поиск     " + (Время2 - Время0) / ЧислоЦиклов + " мсек");
    Сообщить("-------------------------");
56 Михаил Козлов
 
15.03.16
12:09
(3) Получилось 1 000 000 инкрементаций - 4 сек. У Вас - 292 сек (на 1 000 000). Счетчик типизирован.
57 temmy70
 
15.03.16
12:11
(55)
-------------------------
Циклов    1 000 000
Инкремент 0,207147 мсек
Поиск     0,008307 мсек
-------------------------
а какая платформа?
58 temmy70
 
15.03.16
12:18
На локальной машине, 8.2.19.83
-------------------------
Циклов    1 000 000
Инкремент 0,13797 мсек
Поиск     0,004084 мсек
-------------------------

не могу получить я результаты близкие к вашим
59 Ildarovich
 
15.03.16
12:47
(57) 8.2.19.121
(58) Вот обработка http://my-files.ru/x70trg , попробуйте на ней
60 Кирпич
 
15.03.16
13:02
Циклов    1 000 000
Инкремент 0,000306 мсек
Поиск     0,000914 мсек
61 Кирпич
 
15.03.16
13:02
1С:Предприятие 8.2 (8.2.19.130)
62 Кирпич
 
15.03.16
13:32
прикол.

поставил вместо

  Для ё = 1 По ЧислоЦиклов Цикл
        СчетчикСимволов = СчетчикСимволов + 1;    
  КонецЦикла;

такое

  Для ё = 1 По ЧислоЦиклов Цикл
        СчетчикСимволов = ё;    
  КонецЦикла;

скорость выросла почти в 3 раза

Инкремент 0,000123 мсек
Поиск     0,000871 мсек
63 vde69
 
15.03.16
13:34
а теперь попробуй так

  Для ё = 1 По ЧислоЦиклов Цикл
        СчетчикСимволов = 1 + СчетчикСимволов;    
  КонецЦикла;
64 Кирпич
 
15.03.16
13:37
(63) то же самое, что и

СчетчикСимволов = СчетчикСимволов + 1;
65 Dotoshin
 
15.03.16
13:39
(62) Никакого прикола, в первом варианте у тебя выполняется две операции: сложение и присвоение, а во втором варианте только присвоение. Если все это перевести в машинные команды, то для первого варианта можем получить неожиданно больше команд, чем для первого.
66 Кирпич
 
15.03.16
13:40
(65) да знаю я
67 Dotoshin
 
15.03.16
13:41
(66) А чё тогда удивляешься? :)
68 vde69
 
15.03.16
13:42
(64)
мне кажется, что 1с пытается сначала вызвать деструктор для варианта а потом вызвать конструктор для нового типа.
69 Карупян
 
15.03.16
13:44
0.1 мсек для 1 млн операций - о какой оптимизации может быть речь.
Если только о теоретической
70 Кирпич
 
15.03.16
13:46
(67) да просто
(68) и нафига там деструкторы с конструкторами? чо-то умное хотел сказать чтоли? :)
71 Кирпич
 
15.03.16
13:54
я вот занимался когда то интерпретаторами. из моих поделок самый медленный работал с такой же скоростью как и 1с. Он тупо читал команды и гонял на стеке варианты. я вот и подозреваю, что одинесовский работает по такому же принципу.
дешево, удобно и практично.
72 Mr_Rm
 
15.03.16
15:17
Вот байткод 1С для двух вариантов:

//СчетчикСимволов = СчетчикСимволов + 1;
PushLocal    СчетчикСимволов
PushLocal    СчетчикСимволов
PushConst    1
Add
Assign

//Если МассивСпецСимволов.Найти(ТекущийСимвол) = Неопределено Тогда КонецЕсли
PushLocal    МассивСпецСимволов
PushLocal    ТекущийСимвол
SetParamsCount    1
CallObjectFunction    9
PushReturn
PushUndefined
EQ
JZ    174
Jmp    174
174:

А как это выполняется внутри интерпретатора - 1С только знает.
Проблемы невозможно решaть нa том же уровне компетентности, нa котором они возникaют. Альберт Эйнштейн