"накладные расходы" при работе программы

Общие принципы, проектирование, модуляризация, темплейты и шаблоны
Ответить
Artem.spb

Activity Автор
professor
professor
Сообщения: 3393
Зарегистрирован: 31 июл 2011, 23:05
Награды: 2
Версия LabVIEW: 12-18
Благодарил (а): 49 раз
Поблагодарили: 172 раза
Контактная информация:

"накладные расходы" при работе программы

Сообщение Artem.spb »

Работа над очередным проектом и дискуссии с IvanLis сподвигли на небольшое тестирование.
Но сначала немного воды.
По моему субъективному мнению программисты делятся на 10 категории.
1 программируют на :labview:
10 программируют на С.

Те, кто начинал на "тексте" порой не врубаются в поток данных и злоупотребляют локальными/глобальными переменными. В универе нам сказали дивную фразу "я буду программировтаь на паскале, даже если это будет С". Тут примерно то же самое.

С другой стороны, мне "повезло" начинать с :labview:, но вот с классами я до сих пор толком не подружился. Уже года три их использую, но в качестве удобной обёртки на кластеры, чтобы не загромождать ПУ. Ведь чем дальше и больше проекты, тем больше переменных приходится хранить. И тем больше разрастаются typedef-ы. Но порой возникает вопрос «а надо ли»? Сколько «стоит» мне каждый класс, а точнее, его вызов. И вот, наконец, руки дошли до проверки.
Итак, к делу. Что проверяем: сколько времени тратит система на вызов конкретной функции. Для чистоты эксперимента данные должны меняться, иначе оптимизатор наоптимизирует и ничего вызывать не будет. С другой стороны, сама функция должна работать минимальное время, иначе сложно будет отделить мух от котлет. Поэтому выбирают обычный инкремент.
Дальше, данные обычно запрятаны в кластеры, размер которого «а фиг его знает», потомучто могут быть и массивы и строки и т.п. Поэтому «рабочую» переменную прячу между двух элементов «неопределённой» длины.
Список вариантов работы
1. провода. Самое первое и простое. Сколько «стоит» гонять данные по регистрам.
2. кластер. Появляются при усложнении программ. во что обойдётся разобрать/собрать для изменение одного элемента.
3. in place. Аналогично. Предполагается, что этот метод будет быстрее предыдущего.
4. просто функция. Появляется, когда БД уже не влезает на экран.
5. просто функция с in place. Аналогично с 2-3, но с обёрткой в виде простой функции.
6. статический класс. То же самое, что 4, но в виде класса.
7. статический класс с in place. То же самое, что 5, но в виде того же класса.
8. динамический класс. = 6, но с возможностью override
9. динамический класс-наследник с вызовом родителя. Тут непонятно, что тестирую , но т..к прямого доступа к данным родителя нет, проверю такой способ.
10. динамический класс-наследник. В классе появляется новая переменная. Её и увеличиваю.
11. динамический класс-наследник с доступом к данным. У родителя появляются функции get/set. С их помощью и увеличиваю исходную переменную.

Весь код рисовать тут не буду, в принципе функции примерно так выглядят.
cluster.png
cluster.png (11.89 КБ) 5893 просмотра
А это весь тестер.
main.png
Для пущей достоверности (и чтобы не выключать везде отладку руками) делаю ехе.
Теперь результаты.
results.PNG
Ожидаемо провода оказались самыми быстрыми.
Разбор кластера неизбежно тянет расходы. Тоже в принципе ожидаемо. Неожиданно in place тратит на работу с кластером больше времени.
inplace.PNG
inplace.PNG (6.58 КБ) 5893 просмотра
вызов функции «стоит» 10^-5c. В 20-30 раз дольше, чем просто кластеры, но параноиком быть не надо, это не повод создавать спагетти-диаграммы. in place и тут подводит… Проверял на массивах длиной 500 и 1 000 000 элементов, цифры схождие, так что объёмы передаваемых данных не влияют на скорость вызова функции.
Дальше самое интересное. Стоит функции стать классом, как она замедляется процентов на 20-30. А in place наконец-то обгоняет unbandle.
Но стоит функции стать динамической, как скорость вызова падает в три раза.
Особо интересно выглядят 9 и 11. «поиск» родителя и его вызов вполне объясняют такой рост времени вызова. Но что странно: вызов внутри функции ещё двух функций родительского класса не замедляет работу, даже наоборот. 8 (изменение переменной в «надстройке») работает чуть дольше, чем 11 (изменение переменной родителя). Впрочем, объяснение скорости нашёл, data member access работают через inline.

выводы: не всё так страшно. Если функция выполняет существенную работу, то затраты на её вызов позволительная роскошь в угоду удобству программирования/отладки.
С другой стороны, если важна скорость работы, то совсем мельчить не стоит, много ресурсов будет тратиться на вызовы, а не полезную работу, что и так было известно, просто в очереднйо раз подтверждаем этот факт.
Ну а классы… пора их осваивать серъёзно :)

Ну и самое непонятное в этом тесте: почему массивы уползают со своего места после билдера.…
vi.PNG
vi.PNG (7.73 КБ) 5893 просмотра
exe.PNG
exe.PNG (7.67 КБ) 5893 просмотра
Тестировал на LV16. Для желающих погонять прикладываю и 12
комменты и предложения ожидаются.
Вложения
speed_compare.zip
исходники 16
(197.78 КБ) 159 скачиваний
12.zip
исходники 12
(139.36 КБ) 151 скачивание
Artem.spb

Activity Автор
professor
professor
Сообщения: 3393
Зарегистрирован: 31 июл 2011, 23:05
Награды: 2
Версия LabVIEW: 12-18
Благодарил (а): 49 раз
Поблагодарили: 172 раза
Контактная информация:

Re: "накладные расходы" при работе программы

Сообщение Artem.spb »

Небольшое дополнение в пользу классов, вспомнил что не так давно проверял, стоит ли злоупотреблять вызовами по ссылке.
Редко, но случается так, что до исполнения кода не известно, какая функция понадобится. или надо добавить универсальности, чтобы можно было менять исполняемую функцию "на ходу".
В простых случаях вопрос решается кейсами. В более сложных вариантах можно использовать call by ref с подменой исполняемой функции. Ну и само собой возникает вопрос скорости. Откопал свой старый тест. Сначала функцию вызываю как subVI, потом два раза по ссылке. Функция «a+b» опять же для чистоты эксперимента.
Время исполнения различается на порядок (практически точно 10 раз), результат стабильный при нескольких повторах теста.
Вспоминаем «динамические» классы. Там падение скорости примерно раз в 5. Итого, классы в таких ситуациях использовать выгоднее.
refVSsubVI.PNG
refVSsubVI.PNG (5.07 КБ) 5864 просмотра
Аватара пользователя
IvanLis

Activity Professionalism Tutorials Gold Man of the year 2012
Автор
guru
guru
Сообщения: 5462
Зарегистрирован: 02 дек 2009, 17:44
Награды: 7
Версия LabVIEW: 2015, 2016
Откуда: СССР
Благодарил (а): 28 раз
Поблагодарили: 86 раз

Re: "накладные расходы" при работе программы

Сообщение IvanLis »

По поводу In Place Element Structure была тема: http://labviewportal.org/viewtopic.php?f=87&t=3404
Но было это давно и судя по выводам, с ростом версии LV выигрыш должен стать более существенным.
Аватара пользователя
Kosist

Activity Gold
expert
expert
Сообщения: 1236
Зарегистрирован: 21 фев 2011, 23:44
Награды: 2
Версия LabVIEW: 2013-2020
Благодарил (а): 23 раза
Поблагодарили: 30 раз
Контактная информация:

Re: "накладные расходы" при работе программы

Сообщение Kosist »

Artem.spb писал(а):Уже года три их использую, но в качестве удобной обёртки на кластеры, чтобы не загромождать ПУ. Ведь чем дальше и больше проекты, тем больше переменных приходится хранить. И тем больше разрастаются typedef-ы.

А вот это Вы зря... В качестве обертки нужно subVI тогда использовать, меньше вреда будет... Ибо это - в корне неправильное использование классов. Ведь классы нужны для ООП, а заменяя кластеры на классы - Вы не получаете ООП, Вы все так же следуете процедурному подходу.
Это для меня немного "больная тема", т.к. приходиться поддерживать код, в котором используется один класс, внутри него - мега кластер, и вокруг него - куча методов. А создатель сего творения был уверен, что он сделал приложение в ООП стиле. Ага...
Ведь вместо того, чтобы, например, увеличивать к-ство элементов в кластере -> нужно создать правильную иерархию классов, и "наращивать" количество данных вглубь иерархии, а не раздувать количество данных в родительском классе. И т.д., и т.п.
Переход на ООП всегда болезнен, но если не пытаться, то ничего не выйдет... А просто пряча функции и данные за классами, код больше проигрывает, чем получает - особенно если его будет поддерживать человек, который привык использовать классы правильно.
Artem.spb писал(а):Редко, но случается так, что до исполнения кода не известно, какая функция понадобится. или надо добавить универсальности, чтобы можно было менять исполняемую функцию "на ходу".
А по этому поводу очень интерестная тема есть в LabVIEW примерах версии >= 2016. C:\Program Files (x86)\National Instruments\LabVIEW xxxx\examples\Channels\Replacing The Function At The Heart Of An Algorithm At Run Time -> там есть серия примеров, как заменять функции "на лету", плюсы и минусы, и т.д. Интерестно, и жаль что так спрятано в примерах - ведь многие об этих подходах и не догадываются, или не считают нужным использовать...
Мы делили апельсин - много наших полегло...
Artem.spb

Activity Автор
professor
professor
Сообщения: 3393
Зарегистрирован: 31 июл 2011, 23:05
Награды: 2
Версия LabVIEW: 12-18
Благодарил (а): 49 раз
Поблагодарили: 172 раза
Контактная информация:

Re: "накладные расходы" при работе программы

Сообщение Artem.spb »

Kosist писал(а): А просто пряча функции и данные за классами, код больше проигрывает, чем получает - особенно если его будет поддерживать человек, который привык использовать классы правильно.
как говорится, пруфлинк в студию.
в чём проигрывает код?
то, что человек проигрывает - вопрос субъективный. Я вот почти все коды критикую "да кто ж так программирует?". Я даже свои старые исходники открываю: "это что, я кодил???"
А по этому поводу очень интерестная тема есть в LabVIEW примерах версии >= 2016
пример давно уже изучал, красиво сделано.
Artem.spb

Activity Автор
professor
professor
Сообщения: 3393
Зарегистрирован: 31 июл 2011, 23:05
Награды: 2
Версия LabVIEW: 12-18
Благодарил (а): 49 раз
Поблагодарили: 172 раза
Контактная информация:

Re: "накладные расходы" при работе программы

Сообщение Artem.spb »

Kosist писал(а): Ведь вместо того, чтобы, например, увеличивать к-ство элементов в кластере -> нужно создать правильную иерархию классов, и "наращивать" количество данных вглубь иерархии, а не раздувать количество данных в родительском классе. И т.д., и т.п.
раз пошла такая пьянка, дайте "совет старшего брата". Тут у меня как раз затык. Начинаю разбиваnь данные на классы и...
для примера
класс 1 = класс 2 + класс 3 + класс 4
класс 4 = класс 5 + класс 6
И в программе я работаю с классом 1.
нужно вызвать метод класса 6.

Варианта два в моей голове.
1) класс 1 имеет метод, вызывающий метод "4", который вызывает "6"
итого, на вызов одной функции я пишу 3 :crazy:

2) то, что в текстах выглядит "красиво" класс1.класс4.класс6.нужныйМетод
только в :labview: это не столь элегантно и опять же надо вызвать последовательно 4 функции (три из которых - data member access)
Аватара пользователя
Kosist

Activity Gold
expert
expert
Сообщения: 1236
Зарегистрирован: 21 фев 2011, 23:44
Награды: 2
Версия LabVIEW: 2013-2020
Благодарил (а): 23 раза
Поблагодарили: 30 раз
Контактная информация:

Re: "накладные расходы" при работе программы

Сообщение Kosist »

Artem.spb писал(а):как говорится, пруфлинк в студию.
в чём проигрывает код?
то, что человек проигрывает - вопрос субъективный. Я вот почти все коды критикую "да кто ж так программирует?". Я даже свои старые исходники открываю: "это что, я кодил???"
Это как на игровом топовом компьютере смотреть только видео в ютюбе. Как бы можно, все работает - но мощные ресурсы не используются, и тогда вопрос, нужны ли такие ресурсы вообще?
Код не проигрывает в производительности, но в целом это как бы перебор, overkill. Т.е. мощный подход, а используется для простых целей. Это как иметь Ферарри, и ездить по городу 40 км в час, ни разу не выжав газ в пол за городом ))))
Artem.spb писал(а): раз пошла такая пьянка, дайте "совет старшего брата". Тут у меня как раз затык. Начинаю разбиваnь данные на классы и...
для примера
класс 1 = класс 2 + класс 3 + класс 4
класс 4 = класс 5 + класс 6
И в программе я работаю с классом 1.
нужно вызвать метод класса 6.

Варианта два в моей голове.
1) класс 1 имеет метод, вызывающий метод "4", который вызывает "6"
итого, на вызов одной функции я пишу 3 :crazy:

2) то, что в текстах выглядит "красиво" класс1.класс4.класс6.нужныйМетод
только в :labview: это не столь элегантно и опять же надо вызвать последовательно 4 функции (три из которых - data member access)
Да какой же я "старший брат", я ведь только учусь и в комментах умничаю.. Но по идее так и придеться вызывать метод класса 6. Но то же будет и с сабвиайками - если они будут вызываться вложенными, то каждая из них будет вызывать другую...
А текстах это, кстати, будет то же самое. Ведь каждый вызов типа классА.классБ - означает что из класса А Вы можете достучаться до класса Б, а значит там есть accessor для его вызова извне, или спец. методы. Что-то типа этого - https://stackoverflow.com/questions/385 ... ther-class.
Тут вопрос в другом - нужно ли класс 6 постоянно держать внутри класса 1? Может ли быть класс 6 вне класса 4, чтобы класс 1 = класс 2 + класс 3 + класс 6 + (класс 5)? В этом случае все зависит от задачи - зачем построена такая иерархия, и такие связи между классами; оптимальна ли она; не перебор ли это...
Мы делили апельсин - много наших полегло...
Аватара пользователя
taras_33

Activity
professional
professional
Сообщения: 391
Зарегистрирован: 31 окт 2009, 18:25
Награды: 1
Версия LabVIEW: 2019
Поблагодарили: 13 раз
Контактная информация:

Re: "накладные расходы" при работе программы

Сообщение taras_33 »

C:\Program Files (x86)\National Instruments\LabVIEW xxxx\examples\Channels\Replacing The Function At The Heart Of An Algorithm At Run Time
У меня установленном примере ошибка - lesson 4(LV2016)
Очепятка.png
Вообще OOP мощная штука, особенно в связке с actor framework, да и с HAL поработать... Вот почитайте особенно коментарии после статьи...
А вот каналы ни разу не использовал, нужно будет почитать о них (это я все об упомянутом примере из LV2016).
Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots.
So far, the Universe is winning!
Аватара пользователя
IvanLis

Activity Professionalism Tutorials Gold Man of the year 2012
Автор
guru
guru
Сообщения: 5462
Зарегистрирован: 02 дек 2009, 17:44
Награды: 7
Версия LabVIEW: 2015, 2016
Откуда: СССР
Благодарил (а): 28 раз
Поблагодарили: 86 раз

Re: "накладные расходы" при работе программы

Сообщение IvanLis »

Artem.spb писал(а): Начинаю разбиваnь данные на классы и...
для примера
класс 1 = класс 2 + класс 3 + класс 4
класс 4 = класс 5 + класс 6
И в программе я работаю с классом 1.
нужно вызвать метод класса 6.

Варианта два в моей голове.
1) класс 1 имеет метод, вызывающий метод "4", который вызывает "6"
итого, на вызов одной функции я пишу 3 :crazy:

2) то, что в текстах выглядит "красиво" класс1.класс4.класс6.нужныйМетод
Исходя из принципа "наследования", если нужны методы класса 6 в классе 1, то он должен быть включен в иерархию как базовый (или родительский), тогда получится:

Код: Выделить всё

класс 1 = класс 2  + класс 3 + класс 4 + класс 6
класс 4 = класс 5 + класс 6
Ни что не мешает наследовать свойства и методы класса 6 в других (даже множестве) потомках. Свойства и методы можно наследовать полностью, либо только необходимые, можно добавить новые не присущие родителю. Делается это для исключения дублирования (создания множества однотипных сущностей) и инкапсуляции данных (это тянет за собой полиморфизм).

При выстраивании иерархии классов можно придерживаться принципов нормализации данных в реляционных базах данных, т.е. чтобы свойства и методы не повторялись дважды во всем дереве классов. Но и это не аксиома, например в БД не рекомендуется хранить значения вычисляемых полей, но есть такие значения, что приходится перелопачивать кучу данных для их вычисления, по этому "дешевле" написать тригер отслеживающий изменение/добавление записей и запускающий процесс обновления этих вычисляемых (но все же хранящихся в БД) полей, а по запросу выдавать уже готовое значение.

Короче не люблю я эти классы тоже.
Там трактуется все по разному, сколько людей, столько и мнений. Единого - стандартизованного подхода нет. Даже профи не могут придти к единому мнению, некоторые в открытую называют ООП "злом". Используя ОПП надеясь лишь на то, что компилятор поймет тебя верно и сделает все правильно :suicide: , и не придется идти стройным маршем сквозь десяток объектов, чтобы узнать значение параметра суперкласса... :vampire:
Да и прикручивание ООП к языку программирования, который изначально не создавался для этого, на мой взгляд не очень. Есть же языки типа Java, которые изначально создавались как ООП, так там все через классы делается.
Аватара пользователя
Vitekkz88

Activity Silver Автор
expert
expert
Сообщения: 1100
Зарегистрирован: 21 янв 2014, 15:45
Награды: 3
Версия LabVIEW: 12,13,14
Откуда: Томск
Контактная информация:

Re: "накладные расходы" при работе программы

Сообщение Vitekkz88 »

Чтобы прикрутить ООП и модель акторов в проект - нужно хорошо проработать архитектуру самого проекта, ведь эти технологии уместны далеко не всегда. А чтобы не столкнуться с ситуацией вызова метода класса 6 классом 1 - нужно выбрать подходящий шаблон проектирования(он же паттерн) и проработать интерфейсы и сами классы. То, что описал Артём - это классический пример ловушки, в которую разработчик сам себя загоняет.
Мне это напомнило ситуацию, описанную в книге Эрика и Элизабет Фримен "Паттерны проектирования", когда программист писал апликуху с уточками, затем его попросили добавить пару фич(чтоб утки летали и крякали), а потом оказалось что часть уток должны быть резиновые и летать не умеют, одни крякают, а другие нет + добавить разное поведение... и как это привело к рефакторингу всего приложения. Если в ООП-языках типа Java об этом приходится думать постоянно: архитектуру классов и интерфейсов проработать, шаблоны выбрать, что-то допилить или внедрить, то в случае с LabVIEW всё проще.
Проще в том плане, что можно программировать по классике, а можно и через ООП. Отсюда вытекает следующее: LabVIEW не обязывает разработчика использовать ООП-стиль. А коль и по классике всё работает(не надо утрировать и примеров дурацких), то следует сосредоточиться на чистоте кода, например, или на изучении технологий более широкого спектра(отнюдь не LabVIEW-шных). Я аналогично рассуждаю: прикручивание ООП к языку программирования, который изначально не создавался для этого, на мой взгляд не очень.
Если корпоративная этика будет таковой, что ничего кроме LVOOP - то без проблем пересяду на эти рельсы.
Инженер - это открыто светящийся интеллект, свободный и не обидный юмор, это легкость и широта мысли...Это воспитанность, тонкость вкусов, хорошая речь, плавно согласованная и без сорных словечек...
-А. И. Солженицын
Artem.spb

Activity Автор
professor
professor
Сообщения: 3393
Зарегистрирован: 31 июл 2011, 23:05
Награды: 2
Версия LabVIEW: 12-18
Благодарил (а): 49 раз
Поблагодарили: 172 раза
Контактная информация:

Re: "накладные расходы" при работе программы

Сообщение Artem.spb »

IvanLis писал(а): Исходя из принципа "наследования", если нужны методы класса 6 в классе 1, то он должен быть включен в иерархию как базовый (или родительский), тогда получится:

Код: Выделить всё

класс 1 = класс 2  + класс 3 + класс 4 + класс 6
класс 4 = класс 5 + класс 6
Ни что не мешает наследовать свойства и методы класса 6 в других (даже множестве) потомках.
Я говорю о другом. Не о родителях-потомках, а о соединении группы классов в надклассы.
На примерах, чтобы было понятнее.
Класс "Дом" = стены + водопровод + электричество.
электричество = счётчик + проводка + выключатели
ну и т.д.
надо включить свет ->
Дом.электричество.Выключатель.Включить
так там все через классы делается.
звучит как "там всё через ... делается" :)
некоторые в открытую называют ООП "злом"
Ни разу такого не встречал, хотя в ООП не много копался.
Есть подозрение, что дело не в ООП, а в росте сложности сиcтем, что неизбежно тянет вероятность ошибок.
Аватара пользователя
taras_33

Activity
professional
professional
Сообщения: 391
Зарегистрирован: 31 окт 2009, 18:25
Награды: 1
Версия LabVIEW: 2019
Поблагодарили: 13 раз
Контактная информация:

Re: "накладные расходы" при работе программы

Сообщение taras_33 »

Достаточно часто общаюсь с местными инженерами - программистами, как выяснилось они редко используют ООП в чистом виде, только "в связке" с AF, в кавычках потому что сам AF построен на ООП. Этой же стратегии придерживаюсь и я. Помимо программирования на LabVIEW, по работе приходиться заниматься ARM контроллерами... Так вот я не задумываюсь как работает например драйвер тачскрина и "что там внутри", я просто беру библиотеку и использую. Нет ну конечно если ты мазохист и хочется позаниматься ногодрыгом вручную, придерживаясь таймингов, - флаг в руки, но зачем? Вот такую же философию я использую при работе с Actor Framework - для меня это своего рода "драйвер", который предоставляет очень удобный механизм управления параллельными процессами и передачей информации между ними. Кроме того что то добавить/убрать из/в проект-а, при правильной организации архитектуры, достаточно легко - ведь актеры это независимые модули, как следствие экономит кучу времени, а оно очень ценное... Так что Holly-war разводить бессмысленно, каждому свое...

P.S. При изучении AF многое почерпнул из этого примера
Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots.
So far, the Universe is winning!
Аватара пользователя
taras_33

Activity
professional
professional
Сообщения: 391
Зарегистрирован: 31 окт 2009, 18:25
Награды: 1
Версия LabVIEW: 2019
Поблагодарили: 13 раз
Контактная информация:

Re: "накладные расходы" при работе программы

Сообщение taras_33 »

Для подготовки на получение CLD сертификата, в свое время мне рекомендовали книгу Effective LabVIEW Programming. Купил - понравилось. Там есть шесть примеров CLD с подробным разбором кода.
Но я ее здесь упоминаю потому как, помимо всего остального, в книге неплохо объясняется ООП, а в главе 25, достаточно подробно и понятно рассказывается об "Inheritance and Composition" на примере Wash Controller, так что советую. Кроме того прилагаюстя примеры, упоминаемые в книге (после покупки доступен для скачивания архив).
Думаю если порыться и инете, то можно нарыть в pdf формате, возможно даже с примерами - eMule в помощь.
Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots.
So far, the Universe is winning!
Ответить
  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Модели программирования»