Using listeners and signals with Nasal: Difference between revisions

Jump to navigation Jump to search
m
→‎Listeners and Signals: http://flightgear.org/forums/viewtopic.php?f=30&t=19989&p=183776#p183776
m (Link to special directory articles)
m (→‎Listeners and Signals: http://flightgear.org/forums/viewtopic.php?f=30&t=19989&p=183776#p183776)
Line 1: Line 1:
{{Template:Nasal Navigation}}
{{Template:Nasal Navigation}}
== Behind the Scenes of Listeners ==
Polling is only really recommended for properties that change per frame or really often. Otherwise, you will probably want to use listeners or less-frequent polling using a custom timer.
For example, a listener would be quite appropriate for an on/off switch or similar, an update loop for everything that needs to be updated each frame/update (i.e. engine rpm), and if something is changing every frame anyways or is a tied property, you might as well use the update loop for several reasons: besides the fact that it might be necessary, it linearizes your data flow and moves it closer to the use of the data, it makes use of the current known efficiency of getprop(), and I would venture that it seems most familiar to you. I really wouldn't worry about listener efficiency here
The props.Node wrappers are slower than getprop/setprop because there's more Nasal-space overhead. Intuitively, the props.Node stuff should be faster, because of the cached reference - but the getprop()/setprop() code is native C code that uses a heavily optimized algorithm to look up properties (this may change once the props bindings start using the new cppbind framework).
There will certainly be a break-even point, depending on how often properties change - and how many properties are involved. But usually, listeners should be superior to polling at frame rate for properties that do not change per frame.
Keep in mind that listeners are not "background processes" at all - a listener will be triggered by the property tree once a node is accessed, which will invoke the Nasal callback. Timers and listeners are NOT background "processes". They are just invoked by different subsystems, i.e. the property tree (listeners) or the events subsystem (timers). There are other subsystems that can also invoke Nasal handlers, such as the GUI system or the AI code. This all takes place inside the FG main loop (=main thread), not some separate background/worker thread. Which is also the reason why all the Nasal APIs are safe to be used.
Listeners are not actively "listening" at all - there's no "listener watch" running - instead, it works basically like this:
* register a listener for some property named "foo", to call some Nasal code
* which just adds a callback to a property specific vector, NOTHING else.
* once setprop("foo", value) is called
* the property tree is updated
* next the property tree checks if any listeners are registered for that branch
* if there are listeners attached, they are all called (there's basically a vector of listeners)
So listeners are not really "processes" at all - neither background nor foreground: Merely their *callbacks* become processes after being invoked. Otherwise, they're just a vector of Nasal callbacks - which are only ever called if the property is modified. In other words, there's basically zero cost. Listener overhead is mainly determined by the callback's payload - not by listening (which is just checking vector.size() != 0 and calling each element), unless the property is updated frequently (in terms of frame rate)
Admittedly, having many callbacks/listeners attached, could also add up quickly.
So for benchmarking purposes, you can just use a closure to wrap your callback and update your systime() object accordingly, you could provide a separate "timed_listener" function or just override setlistener().


== Listeners and Signals ==
== Listeners and Signals ==

Navigation menu