Имя: Пароль:
IT
 
Простенькая задачка по производительности
0 dimzon
 
09.07.07
11:56
Надеюсь я правильно выбрал раздел форума...

Уважаемые 1С-неги, вот вам пример крайне неэффективного кода:
v8: У кого нибудь есть готовый вариант кодирования/декодирования BASE64?

На AMD Athlon XP 2900+ этот код будет обрабатывать мегабайтный массив НЕ МЕНЕЕ 5 (ПЯТИ) минут !!!

Кто первый догадается почему?
1 Андрюха
 
09.07.07
12:17
Виноваты операции с float или отстутсвие суперконвейеризации?
2 dimzon
 
09.07.07
12:18
(1) это мелочи ;) есть более "узкое" место ;)
3 Андрюха
 
09.07.07
12:30
Рискну предположить, что это узкое место - сам AMD Athlon XP 2900+ :)
4 Череп
 
09.07.07
12:34
Ну, узкое место во первых Pow(...), во вторых, говорят, целочисленная арифметика не особо быстра.
В третьих функция "получитьсимволпокоду" реализованна совсем ужасно.

Ну и вообще, алгоритм по моему проще.
5 Аштитипи
 
09.07.07
12:34
Ребята, наших бьют
6 dimzon
 
09.07.07
12:34
(3) Неа ;)
Ну так что, ни у кого идей больше нет?
7 Господин ПЖ
 
09.07.07
12:35
(+3) Надо это дело на PS3 запускать...
8 dimzon
 
09.07.07
12:35
(4) Ну по мелочи там много тормозов но есть МЕГАТОРМОЗ ;)
9 Господин ПЖ
 
09.07.07
12:36
(8) эээ... автор? :)))
10 Vovik
 
09.07.07
12:37
(8)Колись, все равно 99% местных 1сников некрувыает о чем вы
11 Аштитипи
 
09.07.07
12:37
где же наш уля 427
12 Аштитипи
 
09.07.07
12:38
(10) Не надо ,щас приждет пит и скажет ху из Дятел
13 Череп
 
09.07.07
12:39
+4 Pow(...) можно заменить на константы(там мало вариантов)
14 dimzon
 
09.07.07
12:40
(10) а ты выкуриваешь?

в общем так, уважаемые 1С-неги, просьба запустить и померить время выполнения вот такого вот фрагмента кода:

   строка = "";
   Для сч = 0 по 333333 цикл
       строка = строка + "abcd";
   КонецЦикла;
15 Vovik
 
09.07.07
12:45
(14)Нет
16 Vovik
 
09.07.07
12:46
(14)С длинными строками проц плохо работает?
17 Vovik
 
09.07.07
12:46
Лучше Списком?
18 dimzon
 
09.07.07
12:47
(16) тут даже не в длине дело ;) ты скорость то померяй (просто на глазок), а то не поверишь тому что я счас напишу ;)
19 АЛьФ
 
09.07.07
12:48
2(14) А как этот код будет выглядеть в твоем варианте?
20 Череп
 
09.07.07
12:48
(14) В 1С все так плохо со строками?
21 Аштитипи
 
09.07.07
12:50
(18) Ты сломал мне 1с
22 romix
 
модератор
09.07.07
12:50
(14) А в чем проблема-то?
Буфер под строку должен удваиваться при каждой нехватки памяти.
В Дельфи по крайней мере вроде бы так.
В 1С это не так разве?
23 igork1966
 
09.07.07
12:50
(14) Логично если 1С "внутре" использует строки без указания длинны (заканчивающиеся кодом 0). Еще понятне если при s= s1+s2 создается новая строка куда все копируется.  ;-)
24 Vovik
 
09.07.07
12:53
Я помню в накладной считал итог по циклу, и складывал случайно как строку. Вроде все высло и выдавало: нехватка памяти.
25 Аштитипи
 
09.07.07
12:54
(18) Короче Склихасовский
26 Vovik
 
09.07.07
12:54
Скорость замерил кто то или нет?
27 dimzon
 
09.07.07
12:56
(19) на 1С не знаю, на VBScript-е или JavaScript-е могу написать (я не спец по 1С)

(20) тут дело не в 1С а в строках в принципе (тормоза воспроизводятся практически во всех языках)

http://sql.ru/forum/actualthread.aspx?tid=406760&pg=-1#3979851

конкатенация строк в цикле ЕСТЬ ЗЛО!

Итак, что происходит при выполнении операции S=S+"Some Text"

Происходит т.н. ReAlloc (перевыделение памяти):
a) Выделяется область памяти размером = размер(S) + размер("Some Text")
b) В выделенную область копируется S
c) В выделенную область дописывается "Some Text"
d) Адрес дескриптора строки S устанавливается на новую область
e) Старая область памяти, использовавшаяся S освобождается

БОЙТЕСЬ КОНКАТЕНАЦИИ СТРОК В ЦИКЛАХ - ЭТО ОЧЕНЬ ДОРОГО!

(22) НЕ ТАК!!! В Delphi 100% НЕ ТАК, в 1С не знаю, но судя по (21) тоже не так...
(23) Прав ;)

Почитайте что написал мне в ответ на это гений:
http://sql.ru/forum/actualthread.aspx?tid=406760&pg=-1#3980648
"И не рассуждайте пожалуйста про конкатенацию строк - для 1С это стандартный метод и он, уж поверьте, оптимизирован на уровне движка. ;-) Не позорьтесь."
28 АЛьФ
 
09.07.07
12:56
2(26) Но это для 7.7.

стр = стр + "abcd";    142255    155.803802    98.19
Для сч = 0 по 333333 цикл    142257    1.453007    0.92
КонецЦикла;    142255    0.639476    0.40
стр = "";    1    0.000004    0.00
29 Череп
 
09.07.07
12:57
Дааа, это вам не php, где для ускорения вывод в строку направляют, а уж потом в браузер...
30 АЛьФ
 
09.07.07
12:59
2(27) Мда... И вот ты со своими знаниями уверен, что именно это будет "мегатормоз" в коде, на который ссылаешься?
31 Череп
 
09.07.07
13:02
(27) Про все я зыки, это ты зря.
php

   $time111 = getmicrotime();
   $s = '';
   for($i = 0; $i < 100000000; ++$i)
       $s += 'qwer';
   echo "Время генерации всей страницы: " . (getmicrotime() - $time111) . " секунд";


Время генерации всей страницы: 17.8581979275 секунд
32 dimzon
 
09.07.07
13:02
(30) По поводу арифметики - я на неё даже не смотрел ;) А по поводу МЕГАТОРМОЗ - ты  сам убедился сколько займёт сбор строки при обработке 1 мегабайта (не так уж и много для решаемой задачи)
33 Череп
 
09.07.07
13:03
+31 меняем $s += 'qwer'; на $s = $s + 'qwer';
Время генерации всей страницы: 19.2857470512 секунд
34 dimzon
 
09.07.07
13:03
(31) я писал что _практически_ во всех
35 dimzon
 
09.07.07
13:05
(31) просто в php свой менеджер памяти и, судя по скорости - специальная обработка строк, заточенная под быстродействие (буффер выделяется с запасом, представление строк в памяти нестандартное)... специфика применения обязывает...
36 Череп
 
09.07.07
13:07
(34) Пардон, облажался, насмотрелся на ваш 1С )))
$s .= 'qwer';
Паямь заканчивается уже при 10000000 циклов(под скрипт 16 метров вроде выделяется)

На при 8 милионах:
Время генерации всей страницы: 2.28033208847 секунд.

З.Ы. Если такую вещь не оптимизирует компилятор - выкинте его в мусорку. Щас gcc попробую.
37 dimzon
 
09.07.07
13:11
(36) а как ты это на C напишешь? код в студию не забудь!
38 dimzon
 
09.07.07
13:12
(36) и по поводу компилятора - ты здря ;) самому тоже надо думать - это полезно ;)
39 dimzon
 
09.07.07
13:14
НУ ЧТО, ГОСПОДА, ПРИЗНАЙТЕСЬ ЧЕСТНО - Я ВАС УДИВИЛ?
40 АЛьФ
 
09.07.07
13:14
2(39) Ни капли.
41 АЛьФ
 
09.07.07
13:15
+(40) Ну, разве только тем, что завел отдельную ветку ради такого пшика.
42 Череп
 
09.07.07
13:15
C++ (gcc 4...)

string S;
for(long int i = 0; i < 50000000; ++i)
   S += "qwer";

~3 сек, даже меньше.
Если ставить больше циклов - память кончается, начинает свопать, тормозить.
43 Череп
 
09.07.07
13:16
+42 50 метров * 4 байта = 200 метров . Свободно порядко 300, так что память используется достаточно оптимально.
44 dimzon
 
09.07.07
13:19
(41) ещё раз - сколько минут у тебя выполнялась конкатегация?

(42) string это что - какой-то класс из библиотеки типов?
S += "qwer"; заменить на  S = S + "qwer";

опять таки, если вместо конкатенации в цикле память СРАЗУ выделить и заполнить не пробовал? попробуй, заметишь как изменится скорость ;)
45 Череп
 
09.07.07
13:20
+42 Прикольно, при S = S + "qwer"; жутко долго. В топку gcc )))
46 dimzon
 
09.07.07
13:20
(43) проблема в том что она (память) перевыделяется многократно...
47 Череп
 
09.07.07
13:21
(44) string - стандартный класс для работы со строками в STL.
48 dimzon
 
09.07.07
13:21
(45) GCC тут не при чём, просто у класса string РАЗНАЯ реализация операторов += и +
49 Череп
 
09.07.07
13:22
(46) Перевыделяется только при S = S + "qwer";
50 Череп
 
09.07.07
13:23
(48) Не спорю. Но компилятор должен оптимизировать такие моменты. Сейчас -O3 попробую.
51 dimzon
 
09.07.07
13:24
(49) скорее всего в реализации оператора += память выделяется с запасом, что значительно уменьшает общее количество ReAlloc-ов
52 dimzon
 
09.07.07
13:25
(50) попробуй ;)
хочу заметить что достаточно большая скорость для С++ это заслуга именно реализации  STL ;)
53 Sabron
 
09.07.07
13:27
Для сч = 0 по 33333 цикл
      стр = стр + "abcd";
  КонецЦикла;  
15.882 сек.

  Для сч = 0 по 33333 цикл
        Стр=СтрЗаменить(Стр,"abcd","abcdabcd");
  КонецЦикла;  
5.486 сек.
54 Череп
 
09.07.07
13:29
(52) Не спорю. Блин, не могу найти где в KDevelop -O3 выставляется.
55 dimzon
 
09.07.07
13:29
(53) хм, подозрительно быстро...
а что за проц? сколько памяти?
56 Sabron
 
09.07.07
13:31
(55)  Celeron 2.6  1Gb
57 Аштитипи
 
09.07.07
13:33
(56) ТЫ на порядок ошибся :)надо не 33333
58 Череп
 
09.07.07
13:41
+42 А если
   QString S;
   for(long int i = 0; i < 100000000; ++i)
   {
       S += "qwer";
   }
То за 25 сек успевает )))
При этом сжирает почти 700 метров виртуальной памяти
59 Череп
 
09.07.07
13:43
Ладно, все спасибо, провел интерессное иследование производительности, используйте нормальные языки )))
60 dimzon
 
09.07.07
13:45
(58) ты S+= на S = S + замени ;)
61 Череп
 
09.07.07
13:47
(60) Да менял уже. При 100000 циклов начинает жутко жрать процессорное время, при этом не требуя памяти. Чем занимается - непонятно (
62 Nordok
 
09.07.07
13:49
с = "";
 с1= "";
 Сообщить(Текущеевремя());
 Для сч = 0 по 340 цикл
    Для Сч1 = 0 По 1000 Цикл
         с1 = с1 + "abcd";
      КонецЦикла;
   с=с+с1; с1="";  
   КонецЦикла;
Сообщить(Текущеевремя());
63 dimzon
 
09.07.07
13:50
(60) перевыделениями памяти ;)
т.е. выделяет новый фрагмент, копирует в него содержимое из "старого", дописывает в конец добавляемую строку и освобождает "старый"
в результате кол-во используемой памяти практически не растёт зато огромные расходы времени на выделение фрагментов памяти и копирование :)
64 dimzon
 
09.07.07
13:50
(62) оптимизатор ;)
65 Череп
 
09.07.07
13:51
(63) Но только после некоторого порога, что удивительно.
66 Nordok
 
09.07.07
13:54
(64) А че медленно ?
67 dimzon
 
09.07.07
13:56
(65) я так понимаю что с ростом размера копируемого блока ;)
в реальной жизни жопа обычно наступает на значительно меньшем кол-ве итераций но при значительно больших объёмах строк (десятки мегабайт)
например при построении бАльших отчётов...

вообще надо иметь ввиду что это в принципе вредно даже если особо не заметно. Ты вот представь что строки на сервере конкатенируются, для 1-го пользователя даже если не заметно то что будет для сотни...
68 Череп
 
09.07.07
13:56
(66) От чего ушли, к тому вернулись.
69 dimzon
 
09.07.07
13:57
(66) Да не, просто улыбнуло ;)
70 Череп
 
09.07.07
13:58
(67) Я то представляю, что такое оптимизация. Просто пока не смотрел на нее со стороны поблеммы выделения памяти для временных переменных.
71 dimzon
 
09.07.07
13:59
я тут на .NET написал, счас дождусь только завершения...
72 France
 
09.07.07
13:59
(4) кто ж про целочисленную арифметику такую фигню сказал?.. плюнь ему в глаз, ибо - целочисленная арифметика - самая быстрая...
73 Череп
 
09.07.07
14:01
(72) Не, там именно в вычислении остатка от деления тяжело. Хотя, возможно это было в другой теме. Не помню уже.
74 France
 
09.07.07
14:02
(73) остаток от деления при целочисленных операциях?)))
75 dimzon
 
09.07.07
14:02
вообще судя по скоростям в 1С для строк всё-таки применяются какие-то трюки... но со StringBuilder-ом из .NET они всё равно не сравнятся ;)
76 dimzon
 
09.07.07
14:03
(74) а что тебя удивляет?
7/5 = 1 и 2 в остатке
77 Череп
 
09.07.07
14:04
(76) Как это еффективно посчитать на процессоре?
78 Череп
 
09.07.07
14:06
+77
7 - (7 div 5) * 5
???
79 dimzon
 
09.07.07
14:09
(78) вообще у процессора есть специальная команда... и в НОРМАЛЬНЫХ языках есть специальный оператор ;) а как в 1C - не знаю
80 Череп
 
09.07.07
14:12
(79) А как по твоему в процессоре эта команда реализованна? В том то и дело, что я что-то не помню такой команды в стандартном наборе инструкций, значит она реализованна в сопроцессоре.
А в данной задаче остаток от деления в принципе не нужен, все можно решить операциями с битами(которые здесь как раз заменены этим убожеством)
81 dimzon
 
09.07.07
14:13
Вот код на C#

           System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
           String s = "";
           sw.Start();
           for (int i = 0; i < 333333; ++i)
               s = s + "abcd";
           sw.Stop();
           long t1 = sw.ElapsedTicks;

           System.Text.StringBuilder sb = new StringBuilder();


           sw.Reset();
           sw.Start();
           for (int i = 0; i < 333333; ++i)
               sb.Append("abcd");
           s = sb.ToString();
           sw.Stop();

           MessageBox.Show(t1 + Environment.NewLine + sw.ElapsedTicks);


Вот результат:
---------------------------

---------------------------
7437893323

126714
---------------------------
ОК  
---------------------------
82 Череп
 
09.07.07
14:15
(81) Давай 10 милионов )
83 dimzon
 
09.07.07
14:16
(79)
читаем http://help-site.com/local/ASMTUT.TXT

DIV    Divides two unsigned integers(always positive)
IDIV    Divides two signed integers (either positive or negitive)

Syntax:
   DIV register or variable
   IDIV register or variable

This works in the same way as MUL and IMUL by dividing the number in AX by the
register or variable given. The answer is stored in two places. AL stores the answer
and the remainder is in AH. If the operand is a 16 bit register than the number in
DX:AX is divided by the operand and the answer is stored in AX and remainder in
DX.
84 dimzon
 
09.07.07
14:20
(81) только для StringBuilder (для строк повешусь ждать)


           System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
           String s = "";
           System.Text.StringBuilder sb = new StringBuilder();
           sw.Reset();
           sw.Start();
           for (int i = 0; i < 10000000; ++i)
               sb.Append("abcd");
           s = sb.ToString();
           sw.Stop();

           MessageBox.Show(sw.ElapsedTicks + Environment.NewLine + sw.ElapsedMilliseconds);

результат:

---------------------------

---------------------------
3522036

983
---------------------------
ОК  
---------------------------



число - кол-во тактов процессора
85 dimzon
 
09.07.07
14:21
+(84)
итого - 983 милисекунды, меньше 1 секунды ;)

тут (при использовании StringBuilder) скорость растёт ЛИНЕЙНО ;)
86 Череп
 
09.07.07
14:23
(83) Пардон, все уже позабыл ((
87 Череп
 
09.07.07
14:24
(85) А памяти у тебя сколько?
88 dimzon
 
09.07.07
14:25
(86) а сопр синус и косинус считает одновременно похожим макаром ;) я в своё время demoscene увлекался ;)
89 dimzon
 
09.07.07
14:26
за этой машиной - 512
90 Череп
 
09.07.07
14:27
(89) А свободной?
91 Череп
 
09.07.07
14:31
(85) 0m0.533s

   string S;
   for(long int i = 0; i < 10000000; ++i)
       S.append("qwer");
92 Череп
 
09.07.07
14:31
+90 А какая машинка?
93 dimzon
 
09.07.07
14:33
(90) process explorer показывает 200
у меня счас тут всякие eMule запущены и студия ещё жрёт...
94 dimzon
 
09.07.07
14:34
AMD Athlon XP 2900+, 2GHz
95 Череп
 
09.07.07
14:37
(94) Куда там моему Sempron 2600(1,6GHz@2GHz)
Но у меня линух
96 dimzon
 
09.07.07
14:37
(91)
у меня кстати код прям из под отладчика и без оптимизаций ;)
97 Череп
 
09.07.07
14:39
(96) Ну дык ты оптимизируй )
Зато с графикой Qt-шные приложения работают заметно быстрее чем .Net
98 Череп
 
09.07.07
14:39
Но .Net заметно удобнее...
99 dimzon
 
09.07.07
14:40
(97) начинаем религиозный спор? ;)
100 dimzon
 
09.07.07
14:40
(98) ещё бы ;)
101 Череп
 
09.07.07
14:44
(99) Ага :)
102 dimzon
 
09.07.07
14:47
(101)
Программирование на C++ — это по жизни хождение по граблям. С рождения и до пенсии. Сначала ты наступаешь на эти грабли постоянно, затем учишься от них уворачиваться, потом изобретаешь какие-нибудь ходули в виде смарт-поинтеров и мелких библиотечек и вот грабли хоть уже и пролетают мимо, но до тебя уже не достают. Ты горд собой, шаг широк, ты думаешь, что это свободный полёт. Но это не так, это всего лишь ходьба на ходулях. Иногда ты всё же цепляешься за какой-нибудь кривой указатель и дружно падаешь со всей своей крутизны на всё те же грабли. Поднимаешься снова и прёшь вперёд как танк.

А мимо по шикарной автостраде проносятся чуваки на новеньких мерсах и бумерах. Ты делашь два широких шага на своих ходулях, они пролетают две сотни метров. Ты смотришь куда бы побезопаснее ступить, они думаю следует или не следует слегка притормозить на следующем повороте. Их путь выстелен грамадным фреймворком, автоматическим сборщиком мусора и полностью безопасным кодом. Твой усыпан протухшими указателями, мемори-ликами и циклическими ссылками. У тебя уходит 50% времени на движение вперёд, 50% на уворачивание от граблей и ремонт ходуль. У них 50% так же на движение (но несравненно быстрое), 50% на изучение марштута, полировку своих тачек и определение стратегии движения.

Они конечно не умеют как ты ловко двигаться по пересечённой местности, но фору они тебе могут дать не слабую. Потому что ты большой специалист по решению мелких задач, а они работают по крупному, т.к. за то же время могут сделать в 2-3 раза больше.


оригинал тут: http://rsdn.ru/Forum/Info.aspx?name=FAQ.philosophy.dotnetvscpp
103 Череп
 
09.07.07
14:59
(102) Никакой инструмент или framework не научат тебя правильно программировать. На данном этапе мне нужен С++, чтобы грамотно освоить ООП, а после паттерны проектирования(большинство книжек с примерами опираются именно на С++ с непростым синтаксисом). А после, можно освоить любой framework за пару недель и писать на нем что тебе вздумается нормальный, расширяемый и модифицируемый код.
104 dimzon
 
09.07.07
15:03
(103) Частично ты прав, частично нет ;) Паттерны в основном на UML и Java (во всяком случае те что я видел)

"А после, можно освоить любой framework за пару недель и писать на нем что тебе вздумается нормальный, расширяемый и модифицируемый код."
Вот насчёт этого реально можно поспорить, но не буду... Скажем так - не всякий грамотный разработчик на С++ это сможет так просто и за 2 недели. Далеко не всякий ;)
105 Череп
 
09.07.07
15:11
(104) Для начала хватит. Остальное по ходу задачи.
UML и Java? Паттерны в общем, для ООП, с целью увеличения структуризации и повторной используемости кода применяются. В любых языках.
106 romix
 
модератор
09.07.07
15:26
(27->22) Хм где же я прочитал что размер буфера удваивается?....
Этого вообще нигде нет что ли?
107 Череп
 
09.07.07
15:28
(106) В STL, у стандартных контейнеров.
108 dimzon
 
09.07.07
17:42
вот отчётик о производительности:

1с 8.1
последняя версия 8.1.8.66
памяти порядка 57 Мб,
начало 09.07.2007 16:46:32
конец 09.07.2007 17:27:12
время = 2 440 секунд
тачка помимо этого задания была нагружена
109 Sol78
 
09.07.07
21:14
Простенькая задачка по производительности
Череп, если ты про мод() - то это команда "%", т.е.
с = а%б
110 Sol78
 
09.07.07
21:15
(109) -> (80)
111 Нэп
 
10.07.07
12:02
(76)
По поводу остатка от деления: в приведенном алгоритме по сути нужно побитовое "И", т.к. ищется остаток от деления на степень двойки. Да и целочисленное деление не нужно тут по аналогичной причине - достаточно сдвига вправо.

(0)
(30)
Говорить что самое узкое место в этом коде - сложение строк - некорректно. Я говорю про конкретно приведенный алгоритм в контексте среды 1С . Запусти замер производительности и увидишь, что самые большие тормоза дают выкрутасы с целочисленным делением и нахождением остатка от деления (ну нет в 1С операций сдвига и битового "И"!).

Даже если код переписать вот так:


   МассивСимволов6Бит = новый массив(64);
   Для сч=1 по 64 цикл
       МассивСимволов6Бит[сч-1] =сред(СтрокаСимволов6Бит,сч,1);
   КонецЦикла;

   Для сч = 0 по кол-1 цикл
       слово = массив[сч*3]*65536 + массив[сч*3+1]*256 + массив[сч*3+2];
       код1 =див(слово,262144);
       код2 =мод( див(слово,4096) , 64 );
       код3 =мод(див(слово,64),64);
       код4 =мод(слово,64);
       стр1 =МассивСимволов6Бит[код1  ];
       стр2 = МассивСимволов6Бит[код2 ];
       стр3 = МассивСимволов6Бит[ код3 ]  ;
       стр4 =  МассивСимволов6Бит[ код4 ];
       строка = строка + стр1+стр2+стр3 + стр4;
   КонецЦикла;

на первом месте по тормозам все равно строчки:

       код2 =мод( див(слово,4096) , 64 );
       код3 =мод(див(слово,64),64);
а операция [строка = строка + стр1+стр2+стр3 + стр4] съедает времени всего в 4 раза больше, чем [стр1 =МассивСимволов6Бит[код1] ] - операция получения значения элемента массива по индексу!

Не вопрос,что на других языках это можно решить быстрее.
Попробуй сделать этот код эффективней используя лишь встроенный язык 1С, а потом уж говори про "пример крайне неэффективного кода".
112 dimzon
 
10.07.07
14:43
Накатал тут резюмирующий пост: Эффективный способ конкатенации строк в 1С

(111) ты несколько неправ ибо ресурсоемкость вычислений растёт прямо пропорционально размеру обрабатываемого массива а затраты на ReAlloc-и по нелинейной зависимости, что-то вроде экспоненты ;)