[Из песочницы] Какой цикл быстрее? Тестируем 1С
Занимаюсь программированием 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. Если использовать цикл «Если» — другие программисты тебя явно не поймут.