LabVIEWForum.de - Alternativen zu globalen Variablen

LabVIEWForum.de

Normale Version: Alternativen zu globalen Variablen
Du siehst gerade eine vereinfachte Darstellung unserer Inhalte. Normale Ansicht mit richtiger Formatierung.
Hi,

da globale Variablen langsam und speicherintensiv sind, habe ich bisher die Variante über ein nicht-initialisiertes Schieberegister in einem SubVI benutzt. Siehe dazu meinen Anhang aus einem früheren Post:
http://www.LabVIEWforum.de/index.php?act=A...st&id=36008

Nun habe ich mich aber gefragt, wieso NI diese Methode nicht auch intern für die globalen Variablen verwendet, wenn sie nur Vorteile hat. Daraus schließe ich, dass ich mit der Geschwindigkeit auch Nachteile erkaufe, über die ich mir aber bisher etwas unklar bin. Folgende zwei kommen mir in den Sinn:[list=1]
[*]Kein Initialisieren. Beim Erstellen der Variable wird diese nicht mit einem Standardwert belegt. Wenn man also ein READ vor einem ersten WRITE ausführen sollte, bekommt man einen undefinierten Zustand.<>
[*]Möglichkeit auf fehlerhafte Race-Conditions bei gleichzeitigem Schreib-Zugriff auf die Variable. Dies wird mit globalen Variablen über das Anlegen einer Speicherkopie vermieden, habe ich das richtig verstanden? Wie entscheidet diese dann, welcher Wert übernommen werden soll, wenn zwei Werte gleichzeitig geschrieben werden?<>
[st]Liege ich mit meinen Vermutungen richtig und gbt es eventuell noch weiter Nachteile?

Weiter Alternativen dazu sind meiner Meinung nach:[list]
[*]Referenzen (schwierig bei Kommunikation über mehrere Programmmodule hinweg und zwischen völlig unterschiedlichen Sub-VIs)<>
[*]FIFOs (funktioniert super, allerdings wird nicht der letzte Wert, sondern der nächste in der Liste abgefragt, was nicht immer zweckmäßig ist)<>
[st]Kennt ihr weitere Möglichkeiten?
' schrieb:[*]Kein Initialisieren. Beim Erstellen der Variable wird diese nicht mit einem Standardwert belegt. Wenn man also ein READ vor einem ersten WRITE ausführen sollte, bekommt man einen undefinierten Zustand.

Falsch. Die sind schon initialisiert beim Laden. LabVIEW intialisiert die nämlich garantiert auf den default Defaultwert für den Datentypen (also null für Zahlen, und leere Arrays und Strings). Dass das manchmal nicht ist was man gern möchte ist ein anderes Problem, aber definiert sind sie eben schon.

Zitat:[*]Möglichkeit auf fehlerhafte Race-Conditions bei gleichzeitigem Schreib-Zugriff auf die Variable. Dies wird mit globalen Variablen über das Anlegen einer Speicherkopie vermieden, habe ich das richtig verstanden? Wie entscheidet diese dann, welcher Wert übernommen werden soll, wenn zwei Werte gleichzeitig geschrieben werden?

Die Möglichkeit besteht auch nicht. Solange das SubVI nicht reentrant ist kann es nur gleichzeitig von einem anderen VI aufgerufen werden. LabVIEW rescheduled (oder wenn diese anderen Aufrufer nichts anderes mehr zu tun haben, blockiert) andere Aufrufer automatisch solange ein non-reentrant SubVI schon von jemandem ausgeführt wird.

Hier ist aber auch gleichzeitig ein möglicher Nachteil. Wenn dieses SubVI nämlich langdauernde Operationen macht (komplexe Berechnungen oder dergleichen) dann werden eben andere Teile des Programms auch aufgehalten.

Zitat:[*]Referenzen (schwierig bei Kommunikation über mehrere Programmmodule hinweg und zwischen völlig unterschiedlichen Sub-VIs)

Referenzen sind in dieser Hinsicht eine katastrophale Verschlimmbesserung. Diese werden immer im UI Thread ausgeführt, können das Programm also extreeeeem verlangsamen und gar blockieren wenn Du irgendwo in Deinem Programm beispielsweise einen Dialog (File Selection oder ein simpler 1 Button Dialog) anzeigen lässt. Die Datenkopie vom Kontrol wird hier ebenso getan als bei einer Globalen, also im Vergleich zur globalen Variable nur Nachteile.

Zitat:[*]FIFOs (funktioniert super, allerdings wird nicht der letzte Wert, sondern der nächste in der Liste abgefragt, was nicht immer zweckmäßig ist)

FIFOs können gut sein. Aber wenn Du es genau wie eine Globale verwendest ist es eigentlich auch nicht unbedingt viel besser, obwohl in LabVIEW 8 sind FIFO so obtimalisiert, dass der Datenbereich der beim Hineineschreiben in die FIFO queue kopiert wurde, automatisch wiederverwendet wird beim Auslesen also eine Kopie weniger ist da schon und wenn Du Daten nicht noch irgendwie anders verwendest (also ohne Verzweigung beim Write FIFO VI) dann wird gar keine Kopie getan. Aber das ist LabVIEW 8.x Funktionalität. In früheren Versionen waren die FIFOs und andere vergleichbare VIs (Notifier) nicht so smart.

Und wenn Dich nur der letzte Wert interessiert ist ein Notifier eigentlich besser. Auch hat das FIFO den Nachteil dass Du einen einmal gelesenen Wert nicht einfach noch mal lesen kannst (oder Du machst einen Peek aber dann muss das FIFO VI genauso eine Kopie machen wie beim Lesen des Notifiers).

Der Vorteil von intelligenten LV2 Style Globalen, wie ich die uninitialisierten Shiftregister VIs nenne, liegt vor allem darin, dass man in diese VIs Intelligenz stecken kann, so dass man wenn man in einem Array nur ein Element überschreiben will dies in diesem VI auch so programmiert und damit jede Kopie von Speicher vermeidet. Wenn Du eine LV2 Style Global genau so verwendest wie eine normale Global, also irgendwo Daten rein und irgendwo anders alle Daten wieder raus, dann sparst Du zwar im Vergleich zu Globalen immer noch eine Datenkopie, ähnlich wie bei Queues, aber optimal ist noch lange anders.

Um bei obigem Beispiel zu bleiben, nehme mal an dass Du ein 10 Millionen Elemente Array in so eine Globale steckst und da gerne ein Element an einem bestimmten Index ersetzen möchtest.

Wenn wir das mit globalen Variablen machen hast Du erstens eine mögliche Race-Condition, (zwischen dem Lesen der Variablen, Verändern und zurückschreiben kann jemand anders ebenfalls diese Variable verändern) und minimal 3 mal soviel Speicher (globale Variable selber, Lesekopie, Schreibkopie).

Bei Verwendung von trivialen LV2 Style Gobals hast Du noch immer die mögliche Race-Condition und doppelter Speicherverbrauch (Variable im Schieberegister, und Lesekopie) vorausgesetzt Du verzweigst den Draht nicht noch vor dem zurückschreiben in die LV2 Style Globale.

Wenn wir aber jetzt eine intelligente LV2 Style Global machen, die ausser den zwei Methoden "Read" und "Write" auch noch eine "Replace Element" Methode hat dann haben wir nicht nur keine Race-Condition mehr, sondern auch keinen extra Speicherbedarf da die Replace Array Funktion innerhalb dieses LV2 Style Global-VIs von LabVIEW automatisch so optimalisiert wird, dass der Buffer aus dem Schieberegister wiederverwendet wird.

Rolf Kalbermatter
Wahnsinn, danke für die vielen vielen Hinweise...! Jetzt bin ich um einiges schlauer!

Auch die Funktion, den Array-Eintrags direkt im Shiftregister zu ersetzen ist genial. Aber irgendwie hätte man da auch selbst drauf kommen können;)Ich fand' es schon immer ziemlich umständlich, erst das komplette Array zu lesen, dann einen Wert zu ersetzen und anschließend das ganze wieder zu schreiben. Anweisungen in textbasierten Sprachen wirken da simpler, obwohl man natürlich auch nicht weiß, was da im Hintergrund abläuft...

Also nochmal: Danke!
' schrieb:Kennt ihr weitere Möglichkeiten?
Ja: Umgebunsvariablen = Weiterentwicklung der globalen Variablen seit V8
Mit Zeitstempel und wirklich Global im Sinne von gültig im Gesamten Netz oder Internet.
Habe leider keine Erfahrungen damit.

Deine Methode mit nicht initialisiertem Schieberegister ist bekannt unter dem Begriff "Funktionale Globale Variable" und wurde hier schon diskutiert.
' schrieb:Ja: Umgebunsvariablen = Weiterentwicklung der globalen Variablen seit V8
Mit Zeitstempel und wirklich Global im Sinne von gültig im Gesamten Netz oder Internet.
Habe leider keine Erfahrungen damit.

Deine Methode mit nicht initialisiertem Schieberegister ist bekannt unter dem Begriff "Funktionale Globale Variable" und wurde hier schon diskutiert.

Umgebungsvariablen scheint mir eine schlechte Übersetzung der Shared Variablen, was Du scheinbar ansprichst. Umgebungsvariablen sind in meiner Erlebniswelt eher so die Dinge die man beispielsweise in einem LabVIEW 8.x Projekt setzen kann. Innerhalb des Projektes werden diese dann benützt um mit der Conditional Compile Struktur je nach dem Code auszuschliessen oder einzubinden. Auf etwas globalerem Niveau sind Umgebungsvariablen zum Beispiel die PATH Variable unter Windows, die von allen Applikationen gelesen werden kann.

Ich weiss zwar nicht ob Umgebungsvariable hier ein offizieller Name ist oder ob der von Dir kommt, aber Netzwerkvariable scheint mir den Sinn der Sache zumindest etwas besser zu beschreiben, auch wenn es natürlich so ist dass die auch lokal zugänglich ist. Aber der Zugrif darauf geschieht in jedem Fall über den Netzwerklayer.

Und was die Performance betrifft treffen alle Nachteile der globalen Variable auch darauf zu, nur wirds noch etwas langsamer, da nun der Zugriff durch die Netzwerklayer gehen muss statt nur innerhalb des LabVIEW Prozessspeichers.

Rolf Kalbermatter
' schrieb:Umgebungsvariablen scheint mir eine schlechte Übersetzung der Shared Variablen, was Du scheinbar ansprichst.
Ich teile Deine Abneigung gegen diese Bezeichnung, da anderweitig bereits reserviert, aber es handelt sich hier wirklich um ein schlechte Übersetzung.
(Erstellen mit "Strukturen")
Die Gültigkeit im Netz ist natürlich nur bei entsprechender Konfiguration gegeben.
Wenn sie lokal verwendet werden, dann sind sie lediglich dadurch geringfügig langsamer als globale V., weil außer der Variablen noch der Zeitstempel herumtransportiert wird - so die Information auf einer Veranstaltung von NI.
Aber ich habe sie selbst noch nicht verwendet.
Ich verwende in meinem aktuellen Projekt einige Shared-Variables und habe bis jetzt keine Probleme damit.
Ich habe einen Bedienrechner und einen Auswerterechner, über die einige Daten ausgetauscht werden. Dies geht am praktischsten mit den Shared-Variables.
Auf dem einen Rechner schreibe ich die Daten rein und auf dem anderen hole ich sie raus.
Das ganze über TCP/IP-Elemente zu programieren wäre etwas schwierig und umfangreich.

Gruß Markus

' schrieb:Ja: Umgebunsvariablen = Weiterentwicklung der globalen Variablen seit V8
Mit Zeitstempel und wirklich Global im Sinne von gültig im Gesamten Netz oder Internet.
Habe leider keine Erfahrungen damit.

Deine Methode mit nicht initialisiertem Schieberegister ist bekannt unter dem Begriff "Funktionale Globale Variable" und wurde hier schon diskutiert.
Referenz-URLs