Pull to refresh

Comments 35

Я в молодости тоже грешил тестами производительности на 1С, даже показывал их менеджерам. Потом перестал заниматься фигней, точнее противоестественным способом реализовывать свои желания и теперь пользуюсь профайлерами на Java ))

А в 1С для удобства читаемости очень подходит ДляКаждого (эдакий for each), грустно, когда вместо него используют что-то другое.
Еще интереснее на это посмотреть с точки зрения C++ :-)
А смешно получилось. Произносится «Си плюс плюс счастливое лицо»
Кстати, а есть ли для С++ профайлер такой же информативный как в 1С? Чтобы время выполнения показывал не по функциям, а по каждой строке кода?
perf top умеет нечто подобное, но не слишком точно.
Но оно нам не слишком нужно, потому что то что не является вызовом функции обычно транслируется в небольшой набор машинных инструкций, оценить затратность которых на глаз довольно просто, особенно имея перед собой информацию о времени выполнения каждой функции.
В циклах небольшой набор инструкций может выполняться довольно долго. Ну да ладно, с оптимизацией. Есть еще одно применение — отладка.

По результатам замера производительности удобно анализировать выполнение кода. Можно сразу увидеть, какие ветки условий сработали, какие блоки кода не выполнялись вообще, и сколько раз прокрутились циклы.

После такого взгляда на код обычная отладка «скаканием» по каждой строке покажется вам унылым занятием.
Именно для этого perf top умеет определять время занятое каждой отдельной инструкцией, этого хватает. Но все-таки такие вещи, как «исполняется ли ветка кода», обычно отладчиком определяют.
Кто мешает поставить точку останова на начало нужной ветки?
Если б знать где упасть… Эта методика нужна до того, как поставить точку останова. То есть вопрос не в том, исполняется ли одна конкретная ветка. Проблема где-то в коде, но точное место неизвестно. По результатам замера можно одновременно увидеть как исполняются все ветки и сразу увидеть проблемное место. И когда уже проблема локализована, можно поставить точку останова на условие (если оно сложное) и определить, почему условие или цикл работает неправильно. Особенно удобно просматривать замеры на больших участках кода. Не знаю, понятно ли будет на небольшом примере.

Вот функция, которая должна найти сумму все чисел от 0 до 99, за исключением числа, переданного как параметр.

	int SumExcept(int x)
	{
1:		int s = 0;
100:		for (int i = 0; i < 100; i++)
100:		{
100:			if (x = i)
100:				continue;
			s += i;
		}
1:		return s;
	}


В функции ошибка — она всегда возвращает 0. Первое, на что можно подумать – цикл не выполнился ни разу. Но прежде, чем ставить точку останова на цикл, давайте посмотрим на замер.

Цикл выполнился 100 раз, то есть проблема не в цикле. Условие так же проверилось 100 раз – это правильно. Но почему-то условие всегда истинно – оператор continue выполнился 100 раз. Итак проблема локализована — она в условии! Ой, как стыдно, вместо равенства оператор присваивания!
Пробегая отладчиком по коду, мы бы увидели то же самое, но в замере мы сразу видим работу всех циклов и условий в один момент времени. Да и точку останова уже можно не ставить — и так все понятно.
Как я уже сказал, такая проблема будет отловлена поиском аннотации perf top частоты использования инструкций типа add/mov, соответствующих строке кода s += i. Но конкретно в этом случае я поставлю точку останова на s += i, так как это и есть полезная нагрузка, а проверка в начале цикла полезной нагрузкой не является.
Я не спорю, что круто иметь возможность посмотреть на статистику по выполнению каждой отдельной строчки, но это не очень хорошо вяжется с C++.
конкретно в этом случае я поставлю точку останова на s += i, так как это и есть полезная нагрузка

Это очень интересная тема, т.к. свое пребывание в отладчике хочется оптимизировать по времени.
Отладчик на s += i не остановится, т.к. выполнение до этой инструкции попросту не дойдет. И нет никаких предпосылок предположить, почему это происходит. В этом примере можно визуально обратить внимание сначала на цикл, а затем на условие, но в реальном коде до полезной нагрузки может быть пару циклов и десяток-другой условий и визуальная проверка невозможна.
Как дальше локализовать место ошибки? Сделать еще одну попытку с точкой останова или начать пошаговую отладку с начала функции?
Я не спорю, что круто иметь возможность посмотреть на статистику по выполнению каждой отдельной строчки, но это не очень хорошо вяжется с C++.
К сожалению, даже профессионалы 1С не используют профайлер для отладки таким способом. Я случайно обратил внимание на эту возможность. Имеет ли смысл статья на хабре?
Действительно с 1С порой складывается очень печальная ситуация. Мне встречались базы, в которых все данные хранились в одном регистре, а вместо ссылок на справочники использовались строки для хранения наименований и прочих данных. Знакомый рассказывал про конфигурацию, использующуюся для начислений в ЖКХ, в которой все было построено на справочниках, без регистров и без документов.
1С и производительность — вещи несовместимые. Поэтому перестаньте заниматься фигней, точнее противестественным образом реализовывать свои нужды, и начните писать так, как вам удобно.
Производительность 1с достаточна для задач, для которых она применяется, а скорость разработки при этом — колоссальная. Никто же кризис на 1с писать не просит, или ядерные реакции считать. Как и реализовывать бух. баланс на UnrealEngine. Видел недавно статью «CRM/ERP/еще какие-то модные буквы» на вордпрессе (правда не читал), представляю объем труда, который был вложен, а также, насколько это далеко от тех букв…
Замер производительности запускает клиент в режиме отладки, как подчиненный процесс процессу конфигуратора, и соответственно, получает сырые данные о скорости исполнения. Т.е. реальные относительно времени исполнения процесса. Измерение же по времени дает оценку времени исполнения относительно операционной системы, в которой может быть запущено еще множество других процессов с индексом вытесняющей многозадачности более высоким, чем процесс исполнения 1С, соответственно и время будет очень размыто, конечно здесь взято среднее, но выполнено только 5 замеров, и погрешность лучше при таких замерах брать не по средней, а по средней квадратичной. Так значительно точнее.

То, что рекурсия не сработала более чем на 2000 вполне ожидаемо — ведь в рекурсивном вызове постоянно происходит пополнение стека, ведь аргументы функции передаются через стек, который на 2000 уже закончился, и началась обработка сборщика мусора + куча перебросов в выделении памяти.
Про рекурсию вы правильно заметили. Действительно, стек не резиновый, а я почему-то не упомянул об этом в статье. Спасибо за дополнение.

На счет точности тоже согласен. При замерах я не запускал и не останавливал ни каких процессов. Согласен, что замер не точный, но я преследовал немножко другую цель. Хотелось наглядно показать, что использование специализированных механизмов, в частности цикла «ДляКаждого», не только упрощает написание кода и последующее в нем ковыряние, но и положительно влияет на производительность.
На самом желе Для Каждого интересно тем, что оно работает не так, как его аналог из .NET for ..in…. for in использут интерфейс IEnumirable, который имплементирован в большинстве коллекций, и реализоация этого интерфейса не позволяет в полученное значение записывать информацию. Т.е.
for (var obj in diction)
{
obj.prop = 1;
}
выдаст ошибку. Однако в 1с это свободно отрабатывает =) всегда было интересно как это реализовано на уровне платформы, но увы, информация закрыта =(
Для Каждого Объект Из Коллекция Цикл
Объект.Свойство = 1;
КонецЦикла
Действительно, любопытно. Но думаю, что платформу если когда-нибудь и откроют, то это будет очень не скоро. А пока остается пользоваться и радоваться. Механизм очень удобный.
Мне кажется вы что-то путаете, нельзя удалять или добавлять элементы в коллекцию во время for/foreach, а св-ва объектов менять, конечно, можно.

Скажем, в java, код:

for (MyClass obj: collection)
{
obj.prop = 1;
}

работает прекрасно. В C# тоже, должен работать.
А можно написать свой модуль на нормальном языке программирования и подключить его?
Тогда появится возможность писать цикл на брейнфаке под 1С… по-моему, это будет чудесно.
Идея интересная. Думаю её можно реализовать через подключение внешних DLL. Возможно, если будет время, реализую. Устрою гонки между родными и внешними циклами.
Это не имеет смысла, т.к. библиотеки подключаются через COM, и время обращения к библиотеке будет дольше, чем исполняемая в ней команда.
А если предположить несколько миллиардов итераций? Возможно время подключения будет компенсировано?
Только в теории, так как такой внешний код не сможет нормально работать с сущностями 1С, а даже гипотетически сложно представить ситуацию, когда в 1С потребуется миллиард итераций, работающих только с числами и строками и никак не использующий объекты самого 1С.

Плюс, мерить производительность циклов в высокоуровневых языках в большинстве случаев никакого смысла не имеет, так как один кривой запрос к базе данных или к сети, будет выполняться дольше любого практического числа итераций.
Начиная с 8.2 есть же NativeAPI. Правда не факт что он по скорости будет намного лучше :)
NativeAPI по сути тот же COM только более красиво подключен и унифицированы вызовы внешних процедур и функций.

Сейчас 1С сделали REST интерфейс на основании протокола OData 3.0, так что может быть будет во много раз удобнее рассчет проводить извне обращаясь к 1С только для записи/чтения. Это по сути как OLE, только не запускает толстый клиент, конечно же, чисто на HTTP вызовах. Обещают скоро и поддержку JSON добавить =)
NativeAPI по сути тот же COM только более красиво подключен и унифицированы вызовы внешних процедур и функций.

Ни по сути, ни по реализации это ни разу не СОМ.
Используются нативные вызовы загруженной в память динамической библиотеки.
Вы немного заблуждаетесь, вот транслятор haxe в 1с, например.
А «для каждого» на разных коллекциях с одной скоростью работает, что ли?
Интересно, что показало бы сравнение на одинаковом железе:
1. Выполнение циклов на клиенте и на сервере.
2. 32-х разрядный и 64-разрядный сервер.
3. Сервер на винде и на линуксе.
Со скорость работы у 1С беда прямо. Недавно сравнивал JSON сериализатор на коде 1С с XML-сериализатором средствами платформы 1С
Сериализация примерно 5 тысяч записей таблицы значений:
JSON 120 секунд
XML 4 секунды
Может кривость реализации сериализации JSON, кто ее писал?
Сомневаюсь. Брались разные разработки с Инфостарт. Выбирал с лучшей скоростью. Большие задержки были на СтрЗаменить: в строке менялись одинарные кавычки на двойные.
Sign up to leave a comment.

Articles