Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Reading Actor Status Data

Hello there,


Lets say I have an actor which is responsible for communicating with a voltage supply. It responds to messages to turn the supply on/off, set the output voltage and frequency etc.


Now, suppose another actor occasionally, but not periodically, wants to know what the voltage output is set to. As I see it there are a few different ways:


- Send a 'Send Me the Voltage' message, perhaps as a self addressed message

- Register to be send perioidic messages (but I don't want to do this)

- Reads the latest value from some form of global variable/DVR that the voltage supply keeps updated

- Use a synchronous message to read the value there and then.


Until now I've been of the understanding that synchronous messages are best avoided so I've not used them. However, I have used DVRs quite a bit and they seem quite clunky. Is it in fact so bad to use a synchronous message in this type of way? Perhaps there is another better way that I've not thought of?  Using the old coffee shop analogy, I don't necessarily want to go off and do something while they make my drink, I'll just wait for it.


Thank you,


Martin

Message 1 of 32
(13,400 Views)

The "actor-oriented" solution is to have your data consumer register to receive "value changed" messages whenever the voltage changes. (That might be on every sample, if you're sampling a voltage signal that varies constantly.) The consumer then stores a local copy of that latest value and uses the local copy whenever it needs to access voltage. You don't have to send a message if the value doesn't change, and you can limit how often the sender checks for value updates. If the voltage supply notifies that actor on value changes or on a sample clock, then it makes sense to send a message to the other actor whenever one of those updates happens.

The reason for using a message is that you shouldn't expose an actor's internal data state to another actor. They should only communicate through messages, and those messages should always (if possible and practical) be asynchronous. Putting the voltage in a DVR and sharing the reference circumvents this design guideline because now both actors have to worry about when the reference becomes invalid. And if you decide to change or augment the way your publisher works, you may also have to redesign your consumer to accommodate the change.

The reason for asynchronicity is that it's a fundamental design characteristic of any "actor". It keeps a lockup or hang in one component from affecting others in the system. If two processes need to be synchronous with one another, it's pretty likely they shouldn't be independent actors but parts of a single actor. Nothing says you have to make every while loop in your application an independent actor.

Message was edited by: David_Staab

Message 2 of 32
(5,252 Views)

David_Staab wrote:

The "actor-oriented" solution is to have your data consumer register to receive "value changed" messages whenever the voltage changes.

I agree with your post... except this part.  While I personally favor this strategy for its simplicity, I wouldn't say it is the "actor oriented" solution.  It is one variation of the observer pattern, not the de facto standard for actor oriented programming.  Actors require a messaging system to communicate with each other; however, the actor model doesn't dictate how the messaging system is implemented.  (Of course, the distinction between actors and the messaging system is blurred in the AF since it defines the messaging system for you.)

Martin wrote:

Until now I've been of the understanding that synchronous messages are best avoided so I've not used them.

Yes, they are "best avoided," for the reasons David mentioned.  It can be safe to use them in limited scenarios as long as you can verify your code behaves as you expect in all situations.  (i.e. Don't only check the happy path.  Figure out what's going to happen when unexpected things occur.)  As always, there's a tradeoff between design purity and business reality. 

May I ask why you don't want to receive updates every time the voltage changes?  Pushing the data out to everyone who needs it is by far the easiest way to manage concurrency.  If you're *really* opposed to it I'd first look into a "Send me the voltage" message.  If that doesn't work well it's kind of a toss up between using a global and using a sychronous message. 

A global is okay as long your voltage supply actor uses the global as a publishing mechanism and not a storage mechanism, and nothing else ever writes to the global.  The downside is that it introduces a second mechanism that bypasses the normal messaging system.  Synchronous messages stay within the existing messaging system, but also carry the risk of extended delays or deadlocks.

0 Kudos
Message 3 of 32
(5,252 Views)

I've run into similar situations many times, typically where there is a data source that updates *very* often and an external process that occasionally needs low-latency access to the current value.

In my experience the "global" solution is often the best here, simply because it is the quickest/easiest to implement and the global itself is constrained to a single source and single listener. IMO that is a decent use-case for a global.

At the other end of the spectrum, using messaging for the same purpose has two significant hassles:

  1. The "quick" solution is for the Voltage Source actor to publish every ValueChange, but this can easily clog up the messaging infrastructure.
  2. A more robust solution might add an intermediate "Filter" actor which recieves all the ValueChange messages but does nothing else, other than responsing to Voltage requests from the downstream actor. This setup offers better performance than relying on quick replies from the Voltage Source actor (which probably has other things to do), but requires more work to implement.
Message 4 of 32
(5,252 Views)

Daklu wrote:

(Of course, the distinction between actors and the messaging system is blurred in the AF since it defines the messaging system for you.)

That's a very good point, and one I obviously never considered since I've only used AF for AOD. I tend to take a purist approach that funnels everything through AF's messaging queue because it provides guarantees of type safety, handling for every message (with Drop Msg Core.vi), etc. But in the abstract, there's nothing about AOD that says you have to use one communications mechanism for the actor's entire public interface.

That said, as long as we're circumventing the framework's intended use, why don't we just define one message class that takes and returns a string parameter and let it be sent to every actor for every purpose? Or a cluster with an ASCII string command and a flattened string payload? It would certainly simplify implementation for lots of corner cases!

0 Kudos
Message 5 of 32
(5,252 Views)

You guys are all nuts. You go through the effort of using the Actor Framework and then settle on a global variable to pass data around. Just bonkers.

Message 6 of 32
(5,252 Views)

I would go for the first version:

1. Send a 'Voltage Request' message to 'Voltage Supply' actor.

2. Receive the 'Voltage' message from the 'Voltage Supply' actor as soon as it is able to answer.

I think you should not be afraid of async messaging. It is the way actor-model works. IMO using it is just the sign that we finally except that the operating system and the underlying hardware has versatile components and we don't have deterministic control over how to use these resources. We just have to trust the system (and the actor-model, that promises to harvest it efficiently) that the async reply to the request will be as instant as possible.

And to keep actors separated and reusable, I would use zero coupled messages for the "Send" messages on both side. In detail it means that:

- You have two actors: 'Voltage Supply' and 'Voltage Reader'

- Make a 'Voltage Request' message in 'Voltage Supply'. Make a zero-coupled message (like: 'Send Voltage Request') that uses the same datatype in 'Voltage Reader', but it should be only an abstract class without implementation for Do.vi.

- Make a 'Voltage' message in 'Voltage Reader'. Make a zero-coupled message (like: 'Send Voltage') that uses the same datatype in 'Voltage Supply', but it should be only an abstract class without implementation for Do.vi.

- Connect the Send and Receive messages with making the the Send message's class to be the parent of the Receive message's class (you can do it directly or indirectly by using a Controller actor), and use message injection at initialization to show the Send messages where their children (the Receive messages) are.

Of course you can skip zero coupled messages and use the normal messages directly in the other actor. I just recommend the zero coupled version if you want to make reusable, reconfigurable actors.

And of course, if you find creating Zero-coupled messages to be complicated and tedious, use an automation tool, like Advanced Message Maker I hate to say it and I start to feel like being a salesman of AMM, but it is really what comes to mind as the easy solution. Sorry if I seem to push it.

0 Kudos
Message 7 of 32
(5,252 Views)

MartinMcD wrote:

Now, suppose another actor occasionally, but not periodically, wants to know what the voltage output is set to. As I see it there are a few different ways:


Until now I've been of the understanding that synchronous messages are best avoided so I've not used them.

Is it in fact so bad to use a synchronous message in this type of way?

There is nothing wrong with using Reply Messages when the use case justifies it.  To avoid potential deadlock issues, specify a timeout.  I don't think there has been a conclusion on the ideal design of an instrument/DAQ Actor.  Consider the case where an analog input card is reading data at a few kHz and constantly logging to disk.  It doesn't make sense to broadcast/copy all of this data when a few Actors in the system need to periodically check what "latest" value was before responding to other messages.  One could "subscribe" and then "unsubscribe" when they want values, but isnt' that the same as a reply message with a timeout?

Daklu wrote:

Yes, they are "best avoided," for the reasons David mentioned.  It can be safe to use them in limited scenarios as long as you can verify your code behaves as you expect in all situations.  (i.e. Don't only check the happy path.  Figure out what's going to happen when unexpected things occur.)  As always, there's a tradeoff between design purity and business reality.

I concur on both of these points:

1. Design the Actor that sends the reply message with a timeout and action if the Power Supply actor does not respond.

2. Keep it simple

I would be interested to hear some other opinions on the use of Actors with instruments/DAQ...

CLA, CTA
0 Kudos
Message 8 of 32
(5,252 Views)

David_Staab wrote:

That said, as long as we're circumventing the framework's intended use, why don't we just define one message class that takes and returns a string parameter and let it be sent to every actor for every purpose?

(I know this comment isn't serious, but I'll answer it anyway.)

It's easy to define one message class for all messages a single actor accepts, but one message for all actors? Hmm... I think you could do it but the sender would have to specify the message receiver when the message is created. On top of that, the message class would statically depend on every single actor and every actor would statically depend on the message class, making a complete mess of your dependency tree.

David_Staab wrote:
Or a cluster with an ASCII string command and a flattened string payload?

I know, how stupid right? I can't believe people still use string/<general type> messages, like string/variant or string/object! (Oh wait... I do use that last one.)

Type safety is great for avoiding runtime type mismatch errors. Unfortunately, custom types (like classes and typedefs) also create static dependencies, and on larger projects that can kill you. There seems to be a strong aversion to all flavors of string/<general type> messages among LV users. For CLAD and low level CLD, I can understand that. The projects tend to be small and the type safety helps them avoid errors. For more advanced developers the best way to reduce actor coupling is to pass messages using only native LV types. That way each actor depends on the built-in types instead of on the custom types defined by each actor. Alternatively, you can define a library of custom data types (string/<typedeffed cluster>) and have all the actors depend on those instead depending on each other.

String/<general type> messages aren't as sexy or flashy as command pattern messages, but don't count them out. They're still very good at things command pattern messages struggle with.

0 Kudos
Message 9 of 32
(5,252 Views)

Daklu wrote:

(I know this comment isn't serious...)

Correct. If I wanted to do any of that, I wouldn't be using AF.

Type safety is great for avoiding runtime type mismatch errors. Unfortunately, custom types (like classes and typedefs) also create static dependencies, and on larger projects that can kill you. There seems to be a strong aversion to all flavors of string/<general type> messages among LV users. For CLAD and low level CLD, I can understand that. The projects tend to be small and the type safety helps them avoid errors. For more advanced developers the best way to reduce actor coupling is to pass messages using only native LV types. That way each actor depends on the built-in types instead of on the custom types defined by each actor. Alternatively, you can define a library of custom data types (string/<typedeffed cluster>) and have all the actors depend on those instead depending on each other.

I 100% agree. That said, AF was designed for type safety, and I believe in using a tool for what it was designed to do. If that tool doesn't suit my needs, I'm more likely to grab or design another tool than use it the wrong way.

String/<general type> messages aren't as sexy or flashy as command pattern messages, but don't count them out. They're still very good at things command pattern messages struggle with.

Again, I 100% agree. I'm just trying to encourage folks to use AF the way it was intended. If AF doesn't suit their needs, NI needs to know so they can change AF or evolve it into a different framework.

Message was edited by: David_Staab

0 Kudos
Message 10 of 32
(5,252 Views)