Pull to refresh

Какой цикл быстрее? Тестируем 1С

Reading time3 min
Views25K
Занимаюсь программированием 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. Если использовать цикл «Если» — другие программисты тебя явно не поймут.
Tags:
Hubs:
Total votes 43: ↑22 and ↓21+1
Comments35

Articles