LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Advice on Actor Scope

I'm digging in to AF again after years of using it horribly wrong. I'm stuck on how to decide on scope for an actor and was looking for any advice on what works for you. What should an actor do? What should it not do? How many things should it do? How long should an actor live?

0 Kudos
Message 1 of 8
(2,852 Views)

That's a good question CanadaGuy,

 

If we go "by the book", an actor is an abstract representation of a process that executes independently of other processes. Procedural programming separates data and the functions that operate on the data. Object-oriented programming is a higher level abstraction that combines data and functions into a single entity called an “object.” Actor-oriented programming takes that a step further, combining data, functions, and threads into a single entity called an “actor.”

 

Good actor oriented designs think in terms of responsibilities. For every piece of data in your system you should be able to identify one actor who is responsible for maintaining it and keeping other actors informed of changes. Remember they can: a) send a message, b) launch another Actor, and c) change how it will respond to the next message it receives.

 

I read you have been using AF for a while now, and I find this post (Actor Framework for Dummies) that might be worth checking. It does include all the "getting started" knowledge that you might already know, but hopefully it gives more insight to the "Why?" of the AF architecture, and compliments the answer I've written. I also took information from the Actor Oriented Design Using LabVIEW course.

 

All the best,

0 Kudos
Message 2 of 8
(2,820 Views)

Hi Oscar, sorry I read your post, then forgot to come back and reply...how rude of me.

 

In the case of AF threads, each thread or actor then is a synchronous set of functions called through messages either internally or external to the actor. These functions would then get executed in the called sequence, until the queue is empty, or otherwise modified. The actor is then either idle (no messages and so does nothing) or active, where the actor blocks immediate execution of a task until its position in the queue is reached.

 

I suppose then the goal of actor design would be to avoid mega actors that execute a single task for a long time, in favor of multiple small tasks where the queue could be modified or interrupted at strategic points in execution.

 

Most of my projects are considered simulations, so there is a lot of computation that takes place. It sounds like perhaps instead of using a single big state machine with a case structure and enums for the states, I should instead let a root actor be the state machine, with nested actors performing each of the states. Have I got this right, or have I misinterpreted things?

0 Kudos
Message 3 of 8
(2,779 Views)

Hello CanadaGuy,

 

To be honest, I have not developed much using AF. I always try to recommend simpler architectures first, unless the application does require multiple developers, or a level of complexity that is worth of the AF/OOP architecture.

 

That being said, the approach you take sounds reasonable to me. Dividing a larger task into smaller ones that can produce concrete pieces of data based on a given input to process can be a good approach to the problem, especially since you can stop them altogether if an error happens.

 

Out of curiosity, how big are your simulations that you can't use a Producer-Consumer, or a simpler QMH/DQMH? As with everything in programming, there are multiple ways of "attacking" a problem when we are programming, and it would definitely be interesting to hear someone else's point of view.

 

All the best,

0 Kudos
Message 4 of 8
(2,769 Views)

A significant part of my interest in AF is for learning a framework that allows more candid asynchronous code and when used properly and AF seems to deliver that, at least from my perspective so far. Another part is to learn enough about it to understand when it is useful and when it isn't. I'll admit that when I initially learned about the AF hammer, everything started looking like a nail.

 

My applications and simulations usually start out quite small and simple, and complexity goes up from there. I can't say I've perfected the Producer-consumer or QMH approaches by any stretch, so I know that I'm not using them in all the cases that perhaps I should. The simulations are usually a big part and are often accompanied by other functionality for browsing results, plotting, etc. Instead of having the Type 1, 2, or 3 application, I would have a single application for Type 1, 2, and 3 combined. This would drastically reduce the amount of redundant code and improve reuse.

0 Kudos
Message 5 of 8
(2,759 Views)

You generally don't replace states with actors- you replace state *machines* with actors. The actor itself is basically a state machine with each state being a method (sort of...). In a traditional state machine, you have a shift register with your "internal" data that is acted upon. In an actor, you still have this shift register, but it's abstracted in the parent that calls Actor Core- your cluster has turned into the Actor's private data. Each method has an input for your Actor's private data object (the "cluster" from the traditional state machine), where it can act upon its internal data, then return the whole Actor object again. Each message you call on an Actor calls one of these Methods. In fact, the Message is just a wrapper around the Method; the Message itself generally doesn't do much (if any) actual work.

 

In a Simulation system, you could set up the Simulation itself as an Actor. The Simulation Actor would run all of your calculations and simulations. You could also have a Plotting actor or a Browsing actor or whatever that launches the Simulation actor, sending it messages to ask it to simulate some "thing".

 

Since Actors are themselves Objects, you can have them inherit. Let's say you have two different types of simulations that act on the same basic data type and return the same basic data type- maybe one is a gravity simulation that returns an object's position, and one is a simulation that includes air resistance. You could have a basic actor called "Gravity simulation" that can handle messages like "Load new data to simulate" and can return messages like "Here's my results". You can then have a child actor that inherits from your base Simulation class that does a simulation with no air resistance. It would override the methods provided by the base simulation class. Similarly, you can have a Simulate with Air Resistance actor that would override the base Simulation class with its own methods.

 

What this gets you is that your caller actor (some form of GUI) can use the same messages to interact with either actor- it doesn't know what type of Simulation that's running! You just have to pick which Concrete actor you want to act upon, and the Send Message functions will dynamically call the correct method for either type of simulation. You have now decoupled your Simulation logic from your Set-up-the-simulation GUI. Similarly, you can have a Simulation Plotter actor that can receive a message that says "Plot this simulation data" with the sim data as a payload. It doesn't care WHAT system calls it- it just knows that it has some sim data to display. Now, technically, your plotting code could just be a simple subVI- it doesn't HAVE to be an actor. Having it be an actor means you can change the data displayed in the window by sending it a new message, or you can have it also send the displayed data to a printer, or whatever. It just gives it a good, solid messaging framework where another actor can ask it to do something else. (Keep in mind: messages are REQUESTS for an actor to do something, not a CONTROLLER for the actor. Each actor should handle its own state.)

 

I hope that helps explain things a bit. I'd HIGHLY recommend MGI's Monitored Actor and Panel Actor toolkits for helping debug actors in general and for creating solid GUI's.

Message 6 of 8
(2,752 Views)

@BertMcMahan wrote:

The actor itself is basically a state machine with each state being a method (sort of...).


It is actually closer to a Queued Message Handler whose state data is maintained in a class and the messages are also classes.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 7 of 8
(2,745 Views)

@crossrulz wrote:

@BertMcMahan wrote:

The actor itself is basically a state machine with each state being a method (sort of...).


It is actually closer to a Queued Message Handler whose state data is maintained in a class and the messages are also classes.


Thank you for that, had a brain fart and described it incorrectly earlier. I got state machine and QMH backwards.

0 Kudos
Message 8 of 8
(2,742 Views)