Нотифьеры, очереди и логика

Общие принципы, проектирование, модуляризация, темплейты и шаблоны
AlexanderKonoval
developer
developer
Сообщения: 257
Зарегистрирован: 03 янв 2014, 19:37
Версия LabVIEW: 2016
Откуда: Украина, Киев
Контактная информация:

Нотифьеры, очереди и логика

Сообщение AlexanderKonoval »

Итак, неплохо так прошёлся лицом по граблям, работая с очередями и нотифьерами.

Есть, значит, у меня нотифьер состояния системы, куда каждая железяка шлёт своё состояние. Естественно, что пишутся изменения состояний по очереди, в одном месте. Естественно, чтобы записывать данные в эту очередь я сделал субВИ, где вызывал очередь, куда записываются изменения.
Софтина работала довольно неплохо. Несколько часов. Потом начинались чудеса.

Софт в общем включает в себя кучу параллельных циклов, потоков, динамически вызываемых :vi: и так далее. Выключается это всё хозяйство в одном месте, при помощи уничтожение нотифьера Stop с параметром Forced=True. И если первые пару часов работы софт выключался хорошо, то после часов так 8-10 - отказывался выключаться напрочь, к тому же за 2-3 дня работы набегало до 200 мб. утечки в абсолютном значении, или же +500% в относительном.
В конечном итоге, через дня 4-5 софт ложился намертво вместе с системой.

В итоге разбора полётов и длительного поиска причины виновник был обнаружен (а вместе с ним и куча кандидатов на эту роль, что тоже хорошо)
Если вкратце, то:
test1.png
test1.png (5.12 КБ) 11810 просмотров
И вроде как всё правильно и логика есть. Вернее, даже не логика, а привычные по :labview: принципы работы - открыл элемент, попользовался, закрыл.

Но внутри меня что-то убеждённо говорит, что правильнее было бы при создании очереди/нотифьера добавлять их параметры (имя, тип данных, ссылка) в какой-то массив. И при вызове функции Obtain Notifier/Queue просто брать и смотреть, есть ли нотифьер с таким именем/типом данных в массиве. И если есть - брать его ссылку оттуда.
Ведь, скорее всего, такой массив таки есть, ведь не создаётся новая очередь с таким именем и типом данных, но остаётся всё та же, просто нам ссылку новую дают.

А зачем нам другая ссылка? Что с ней делать, кроме как не забыть удалить?

Собственно, зачем тему создал. Ну, во-первых, потому что пригорело. А во-вторых, может кто знает, почему славные кодеры из НИ сделали именно так, а не так, как я себе предполагал? Может, как раз-таки и надо новую ссылку каждый раз выдавать, а это я тёмный и ничего не понимаю.
колдооооовствооооо! (С)
Аватара пользователя
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 »

AlexanderKonoval, по идее Get Notifier Status Function может вызываться в любое время.
Т.е. если Вы ее поместите в отдельный цикл, который не имеет задержки, то крутиться он будет с максимально возможной частотой, что может привести к перегрузке процессора и т.д. и т.п.
Borjomy_1

Activity Professionalism Silver
doctor
doctor
Сообщения: 2210
Зарегистрирован: 28 июн 2012, 09:32
Награды: 3
Версия LabVIEW: 2009..2020
Откуда: город семи холмов
Благодарил (а): 27 раз
Поблагодарили: 26 раз

Re: Нотифьеры, очереди и логика

Сообщение Borjomy_1 »

А зачем вы флаг "create if not found? (T)" выставляете в false? Если установлен в True, то, согласно документации, как раз нужный вам функционал и обеспечивается...
Аватара пользователя
Vitekkz88

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

Re: Нотифьеры, очереди и логика

Сообщение Vitekkz88 »

В итоге разбора полётов и длительного поиска причины виновник был обнаружен (а вместе с ним и куча кандидатов на эту роль, что тоже хорошо)
Нуууу, как бы это сказать...Основной виновник это Вы сами. Ток без обид :) Могу посоветовать следующее:
1. Поставьте TRUE для входа Create if not found (или вообще не ставьте ничего, по умолчанию там и так TRUE).
2. Не увлекайтесь цикличным уничтожением и созданием уведомителей/очередей. Это всё-таки не референсы. Возможно такой подход вызывает коллизии.
3. Не используйте лишний раз Flush очереди(очистка работает, но накопленные элементы продолжают храниться в оперативной памяти до уничтожения очереди).
4. Не уничтожайте уведомители и очереди с параметром Forced = True без явной необходимости. Ибо элементы, которые были отгружены в другой поток для извлечения, скорей всего улетят в оперативную память, если не успеют обработаться до уничтожения очереди(исправьте, если ошибаюсь). А цикл скорее всего по кластеру ошибок останавливается и запускается вновь.
5. Тестировать, тестировать и еще раз тестировать.
Ищите проблемы в реализации и механизмах использования блоков очереди и уведомителей. Как правило, если есть недостаток в использовании механизмов синхронизации, то это легко отловить на простом примере. За свой многолетний опыт у меня не было проблем с палитрой синхронизации. Память не утекала, ничего не тормозило и процессор не грузило.
Инженер - это открыто светящийся интеллект, свободный и не обидный юмор, это легкость и широта мысли...Это воспитанность, тонкость вкусов, хорошая речь, плавно согласованная и без сорных словечек...
-А. И. Солженицын
AlexanderKonoval
developer
developer
Сообщения: 257
Зарегистрирован: 03 янв 2014, 19:37
Версия LabVIEW: 2016
Откуда: Украина, Киев
Контактная информация:

Re: Нотифьеры, очереди и логика

Сообщение AlexanderKonoval »

IvanLis писал(а):AlexanderKonoval, по идее Get Notifier Status Function может вызываться в любое время.
Т.е. если Вы ее поместите в отдельный цикл, который не имеет задержки, то крутиться он будет с максимально возможной частотой, что может привести к перегрузке процессора и т.д. и т.п.
само собой. блоки разместил исключительно для отображения принципиальной схемы, что надо закрывать ссылку и на очереди/нотифьеры также.
Borjomy_1 писал(а):А зачем вы флаг "create if not found? (T)" выставляете в false? Если установлен в True, то, согласно документации, как раз нужный вам функционал и обеспечивается...
о какой документации речь? я просто в момент разработки софта находился на том опасном этапе профессионального развития, когда думал, что уже знаю всё, что мне надо о инструментах, которые использую :crazy:

В хелпе написано:
If you wire name, the function searches for an existing queue with the same name and returns a new reference to the existing queue

Ну и тест показывает, что ссылка новая всегда, независимо от того True или False подключен на "create if not found?"
test2.png
а функционал, который даёт False на "create if not found?" мне нужен ради кластера ошибки, если очереди/нотифьера ещё или уже нет. Тогда я либо мягко прекращаю работу модуля, раз очереди, куда он хотел писать, уже нет, либо же жду, пока не появится оная.
Vitekkz88 писал(а):1. Поставьте TRUE для входа Create if not found (или вообще не ставьте ничего, по умолчанию там и так TRUE).
2. Не увлекайтесь цикличным уничтожением и созданием уведомителей/очередей. Это всё-таки не референсы. Возможно такой подход вызывает коллизии.
3. Не используйте лишний раз Flush очереди(очистка работает, но накопленные элементы продолжают храниться в оперативной памяти до уничтожения очереди).
4. Не уничтожайте уведомители и очереди с параметром Forced = True без явной необходимости. Ибо элементы, которые были отгружены в другой поток для извлечения, скорей всего улетят в оперативную память, если не успеют обработаться до уничтожения очереди(исправьте, если ошибаюсь). А цикл скорее всего по кластеру ошибок останавливается и запускается вновь.
коллега, без обид, но всё мимо.

И, как я уже сказал, утечка обнаружена, убрана, всё работает как надо. И я просто хочу понять логику, зачем :labview: штампует новые ссылки на очереди и нотифьеры, а не использует те, которые были созданы раньше. Кроме того, интересует также, почему не происходит сие: If you use Obtain Queue in a tight loop, LabVIEW slowly increases how much memory it uses because each new reference uses an additional four bytes. These bytes are released automatically when the VI stops running. По моим тестам, Request Deallocation также не помогает работает, хотя я не уверен, что правильно и к месту его использовал.

Грубо говоря, у нас, разработчиков нет прямого контроля работы с памятью. Мы должны положиться на работу сборщика мусора :labview: . Только чем больше я с :labview: работаю, тем меньше у меня к этому самому сборщику доверия.
колдооооовствооооо! (С)
Аватара пользователя
Vitekkz88

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

Re: Нотифьеры, очереди и логика

Сообщение Vitekkz88 »

И, как я уже сказал, утечка обнаружена, убрана, всё работает как надо.
Ну дк утечку памяти что вызывало в конечном итоге? Использование блока получения статуса уведомителя что ли? Там же еще какие-то кандидаты были у вас, не?
Инженер - это открыто светящийся интеллект, свободный и не обидный юмор, это легкость и широта мысли...Это воспитанность, тонкость вкусов, хорошая речь, плавно согласованная и без сорных словечек...
-А. И. Солженицын
AlexanderKonoval
developer
developer
Сообщения: 257
Зарегистрирован: 03 янв 2014, 19:37
Версия LabVIEW: 2016
Откуда: Украина, Киев
Контактная информация:

Re: Нотифьеры, очереди и логика

Сообщение AlexanderKonoval »

Vitekkz88 писал(а):
И, как я уже сказал, утечка обнаружена, убрана, всё работает как надо.
Ну дк утечку памяти что вызывало в конечном итоге? Использование блока получения статуса уведомителя что ли? Там же еще какие-то кандидаты были у вас, не?
ну, собственно, создание новых ссылок на очереди и нотифьеры. Грубо говоря, в 3 местах кода 3 раза в секунду создавалась новая ссылка. Что в итоге приводило к сбоям в работе программы. Со сбоями ещё не до конца понял. 1гб+ оперативки оставалось, утекать ещё было куда, а программа уже начинала вести себя не правильно. убрал утечку - всё работает так, как надо. в этом плане ещё копаюсь.
колдооооовствооооо! (С)
Аватара пользователя
Vitekkz88

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

Re: Нотифьеры, очереди и логика

Сообщение Vitekkz88 »

Грубо говоря, в 3 местах кода 3 раза в секунду создавалась новая ссылка.
Каким образом??Вы удаляли ранее созданные очереди, уведомители, а затем вновь создавали их? И делали это 3 раза в секунду?
Или останавливали цикл с SubVI, в которой очередь создавалась, и вновь запускали?
Инженер - это открыто светящийся интеллект, свободный и не обидный юмор, это легкость и широта мысли...Это воспитанность, тонкость вкусов, хорошая речь, плавно согласованная и без сорных словечек...
-А. И. Солженицын
AlexanderKonoval
developer
developer
Сообщения: 257
Зарегистрирован: 03 янв 2014, 19:37
Версия LabVIEW: 2016
Откуда: Украина, Киев
Контактная информация:

Re: Нотифьеры, очереди и логика

Сообщение AlexanderKonoval »

Vitekkz88, эм, нет. очереди и уведомители создаются в одном месте. там же и уничтожаются по окончанию работы программы. В :vi: самого верхнего уровня.

Как я показал в своём втором посте в этой теме, если мы используем Obtain notifier/queue, то мы получаем новую ссылку, независимо от того, была ли эта очередь уже создана ранее, стоит ли у нас "create if not found?" и так далее.

Итого, у меня в :vi: очень глубоко в коде, куда было не рационально вести провод с :vi: верхнего уровня, стояла цепочка Obtain->enqueue, что вызывало +4байта к занимаемой оперативке при каждом вызове, чего я не ожидал. И чего я ещё менее ожидал - сборщик мусора это не чистит.
колдооооовствооооо! (С)
Аватара пользователя
Vitekkz88

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

Re: Нотифьеры, очереди и логика

Сообщение Vitekkz88 »

Итого, у меня в :vi: очень глубоко в коде, куда было не рационально вести провод с :vi: верхнего уровня, стояла цепочка Obtain->enqueue, что вызывало +4байта к занимаемой оперативке при каждом вызове, чего я не ожидал.
То есть вы в цикле каждую итерацию вызывали блок Obtain queue?
Инженер - это открыто светящийся интеллект, свободный и не обидный юмор, это легкость и широта мысли...Это воспитанность, тонкость вкусов, хорошая речь, плавно согласованная и без сорных словечек...
-А. И. Солженицын
Borjomy_1

Activity Professionalism Silver
doctor
doctor
Сообщения: 2210
Зарегистрирован: 28 июн 2012, 09:32
Награды: 3
Версия LabVIEW: 2009..2020
Откуда: город семи холмов
Благодарил (а): 27 раз
Поблагодарили: 26 раз

Re: Нотифьеры, очереди и логика

Сообщение Borjomy_1 »

Итого, у меня в :vi: очень глубоко в коде, куда было не рационально вести провод с :vi: верхнего уровня
А что мешало сделать VI, в которой хранится состояние и обращаться к ней из разных мест в программе? А не использовать нотификатор??? К чему эти усложнения?
AlexanderKonoval
developer
developer
Сообщения: 257
Зарегистрирован: 03 янв 2014, 19:37
Версия LabVIEW: 2016
Откуда: Украина, Киев
Контактная информация:

Re: Нотифьеры, очереди и логика

Сообщение AlexanderKonoval »

Borjomy_1 писал(а):
Итого, у меня в :vi: очень глубоко в коде, куда было не рационально вести провод с :vi: верхнего уровня
А что мешало сделать VI, в которой хранится состояние и обращаться к ней из разных мест в программе? А не использовать нотификатор??? К чему эти усложнения?
не понял, что имеется ввиду. каким образом хранить и как обращаться?

у меня программно-аппаратный комплекс модульный. модулей много. у каждого свои протоколы, состояния и так далее. Состояние модулей в кластере, кластер в нотифьере - удобно для отправки на сервер удалённого контроля. В JSON одним нодом перевёл - на веб-сервис отправил.

ну и очереди для управления каждым отдельным модулем, отправки ему команд и так далее.
колдооооовствооооо! (С)
AlexanderKonoval
developer
developer
Сообщения: 257
Зарегистрирован: 03 янв 2014, 19:37
Версия LabVIEW: 2016
Откуда: Украина, Киев
Контактная информация:

Re: Нотифьеры, очереди и логика

Сообщение AlexanderKonoval »

Vitekkz88 писал(а):
Итого, у меня в :vi: очень глубоко в коде, куда было не рационально вести провод с :vi: верхнего уровня, стояла цепочка Obtain->enqueue, что вызывало +4байта к занимаемой оперативке при каждом вызове, чего я не ожидал.
То есть вы в цикле каждую итерацию вызывали блок Obtain queue?
не каждую. по необходимости. Есть субВИ, внутри которой вызов очереди - упаковка данных для записи в очередь - отправка. Вызывается по необходимости, не каждую итерацию, а по факту изменения состояния модуля.
колдооооовствооооо! (С)
Borjomy_1

Activity Professionalism Silver
doctor
doctor
Сообщения: 2210
Зарегистрирован: 28 июн 2012, 09:32
Награды: 3
Версия LabVIEW: 2009..2020
Откуда: город семи холмов
Благодарил (а): 27 раз
Поблагодарили: 26 раз

Re: Нотифьеры, очереди и логика

Сообщение Borjomy_1 »

Каким образом модули узнают о том, что вы пересоздали нотифайер?
AlexanderKonoval
developer
developer
Сообщения: 257
Зарегистрирован: 03 янв 2014, 19:37
Версия LabVIEW: 2016
Откуда: Украина, Киев
Контактная информация:

Re: Нотифьеры, очереди и логика

Сообщение AlexanderKonoval »

Borjomy_1 писал(а):Каким образом модули узнают о том, что вы пересоздали нотифайер?
я не пересоздаю нотифьер на данный момент.

если вопрос к тому, как используется функционал create if not found - то я обрабатываю ошибку в целях логирования, дебагинга и так далее. Система довольно сложная, работает не выключаясь в идеале всегда. Я принял себе за стандарт, что если я где-то в :vi: нижнего уровня вызываю нотифьер или очередь через Obtain, то всегда ставлю create if not found=false, чтобы получить ошибку, если очередь была уничтожена, утеряна и так далее. конкретно сейчас функционал не используется в полной мере, сделано с задатками на будущее.
колдооооовствооооо! (С)
Ответить

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