http://habrahabr.ru/post/245687/
Занимаюсь программированием 1С уже несколько лет, и тут посетила мысль —
«А не пройти ли какой-нибудь обучающий курс, вдруг в знаниях есть какие-то пробелы, о которых раньше даже и не подозревал»? Сказано-сделано. Сижу, слушаю курс, дохожу до циклических операторов и тут вторая мысль
(да, не часто они у меня появляются) —
«А какой цикл быстрее»? Надо бы проверить.
Итак, я нашел
пять способов, как можно организовать цикл средствами 1С.
Первый вид цикла, назовем его условно
«ДляПо» выглядит так:
Для н = 0 по КоличествоИтераций Цикл
КакиеТоДействия();
КонецЦикла;
Второй вид
«ДляКаждого»:
Для Каждого ЭлементКоллекции из Коллекция Цикл
КакиеТоДействия();
КонецЦикла;
Третий
«Пока»:
Пока н <> КоличествоИтераций Цикл
КакиеТоДействия();
н = н + 1;
КонецЦикла;
Далее вспомнил ассемблерную молодость — цикл
«Если»:
~НачалоЦикла:
Если н <> КоличествоИтераций Тогда
КакиеТоДействия();
н = н + 1;
Перейти ~НачалоЦикла;
КонецЕсли;
Ну и напоследок
«Рекурсия»Процедура РекурсивныйЦикл(н, КоличествоИтераций)
КакиеТоДействия();
Если н <> КоличествоИтераций Тогда
РекурсивныйЦикл(н+1, КоличествоИтераций);
КонецЕсли;
КонецПроцедуры
Естественно, что относить рекурсию к циклам не совсем корректно, но тем ни менее с её помощью можно добиться похожих результатов. Сразу оговорюсь, что в дальнейшем тестировании рекурсия не участвовала. Во первых все тесты проводились при 1 000 000 итераций, а рекурсия выпадает уже при 2 000. Во вторых скорость рекурсии в десятки раз меньше, чем скорость остальных циклов.
Последнее отступление. Одним из условий было выполнение в цикле каких-либо действий. Во первых пустой цикл используется очень редко. Во вторых цикл «ДляКаждого» используется для какой-либо коллекции, а значит и остальные циклы должны работать с коллекцией, чтобы тестирование проходило в одинаковых условиях.
Ну что ж, поехали. В качестве тела цикла использовалось чтение из заранее заполненного массива.
ПриемникТестовогоЗначения = ТестовыйМассив.Получить(н);
или, при использовании цикла «ДляКаждого»
ПриемникТестовогоЗначения = Элем;
Тестирование проводилось на платформе 8.3.5.1231 для трех видов интерфейса (Обычное приложение, Управляемое приложение и Такси).
Результаты для 8.3.5.1231
Интерфейс |
ДляПо |
ДляКаждого |
Пока |
Если |
Обычное приложение |
5734,2 |
4680,4 |
7235,4 |
7263,0 |
Управляемое приложение |
5962,4 |
4882,6 |
7497,4 |
7553,6 |
Такси |
5937,2 |
4854,6 |
7500,8 |
7513,0 |
Числа это время в миллисекундах полученное с помощью функции
ТекущаяУниверсальнаяДатаВМиллисекундах(), которую я вызывал до цикла и после его завершения. Числа дробные, потому что я использовал среднее арифметическое пяти замеров. Почему я не использовал Замер производительности? У меня не было цели замерить скорость каждой строчки кода, только скорость циклов с одинаковым результатом работы.
Казалось бы и все, но — тестировать так тестировать!
Результат для платформы 8.2.19.106
Результаты для 8.2.19.106
Интерфейс |
ДляПо |
ДляКаждого |
Пока |
Если |
Обычное приложение |
4411,8 |
3497,2 |
5432,0 |
5454,0 |
Управляемое приложение |
4470,8 |
3584,8 |
5522,6 |
5541,0 |
В среднем платформа 8.2 на 25% быстрее, чем 8.3. Я немножко не ожидал такой разницы и решил провести тест на другой машине. Результаты приводить не буду, в можете сами нагенерировать их с помощью
вот этой конфигурации. Скажу только, что там 8.2 была быстрее процентов на 20.
Почему? Не знаю, дезасемблировать ядро в мои планы не входило, но в замер производительности я все же заглянул. Оказалось, что сами циклические операции в 8.3 проходят несколько быстрее, чем в 8.2. Но на строке
ПриемникТестовогоЗначения = ТестовыйМассив.Получить(н);
то есть при считывании элемента коллекции в переменную происходит значительное снижение производительность.
В итоге:
Процентное соотношение скорости циклов
ДляПо |
ДляКаждого |
Пока |
Если |
78,97% |
64,57% |
99,57% |
100,00% |
К чему всё это? Для себя я сделал несколько выводов:
1. Если есть возможность использовать специализированный цикл — «ДляКаждого», то лучше использовать его. Кстати, сам по себе он отрабатывает дольше чем другие циклы, но скорость доступа к элементу коллекции у него на много выше.
2. Если заранее знаешь количество итераций — используй «ДляПо». «Пока» отработает медленнее.
3. Если использовать цикл «Если» — другие программисты тебя явно не поймут.