Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

I don't understand how to code without blocking calls

I'm surprised as to how little seems to be written about this, at least what I can tell from this message board and Google.   One of the most fundamental things about AF programming is not doing blocking (send and receive) messages.  But I just don't get how to write code without it.  Our code is a large set of synchronous code mixed with an increasing amount of Actors (most of which are just front ends wrapping old existing synchronous code), that probably has a big effect on how I think.

 

The problem of the day, which is pretty typical of the kinds of issues we have:

Display Manager Actor.lvclass -  Receives messages to open and close displays.   Holds such information as how many open displays there are, their display settings, which entity owns open displays.

 

Other entities (some Actors, some synchronous code) - Send messages to open displays with certain settings.  Need to get the display settings to store them away for later when they want to open displays again.  Send messages to close displays.  

 

The problem is how to get information from the display manager such as number of open displays, settings, and such.   From the readings it sounds like every entity is supposed to send query messages up a tree, and some root actor eventually repeats them down to the display manager, which in turn then sends the information up the tree, and it gets repeated back down to the entity that wanted to know.   But all the while, the code that needs to know that can't be sitting there waiting for it, instead is has to just stop what it's doing and go idle until the message with the display settings comes in, then it needs to return to where it was when it needed the information and start using it.    That sounds crazy complicated.  If it's not an Actor it's even more confusing to me how this all would work. 

 

I'm thinking that =an alternative is for the display manager to constantly broadcast out the display settings every time they change to every entity that might ever want to know, that way the info will be there.  But that sounds absurd as well.

 

I must be thinking about AF programming wrong because it seems unlikely that such a complex architecture is what is expected,but I haven't found clear explanations of how to do it right.  Help?

Message 1 of 15
(1,756 Views)

Just for comparison, I don't use AF but consider my designs and framework to be "actor oriented", and the way would code this is:

  • Have the top-level code launch the Display Manager
  • Pass this Manager to the components that need to use it
  • Components will freely use blocking calls to the Manager

Your Display Manager can be thought of as a "shared resource" or as a "server" with multiple clients.  Literature on the AF tends to focus on "peer to peer" relationships; blocking calls on a peer are dangerous as the peer may make a blocking call on you.  But blocking calls on a shared resource are fine, as the resource never makes a call on you.

Message 2 of 15
(1,718 Views)

Really?  It's considered ok to make block calls to Actors as long as those Actors aren't making calls back to you?   That's considered acceptable design?   This is the first time I've read such a thing, I thought everything I've read was clear that block calls are always and forever a code smell that should be eliminated.

0 Kudos
Message 3 of 15
(1,683 Views)

Maybe You could send a sketch of your application.
I don't understand why You should mix asynchronous part with synchronous part.
I would make it so that the synchronous part runs in a loop in the Actor Corel.vi. The asynchronous Actor actions called by Recieve Message should really be as fast as possible, in my opinion.
Then it's not clear to me why your data generating actors need to know the settings of displays. I would give this responsibility to Display classes (may be to Display Manager), because it affects them. If the data volume is not too big, the producers can always send everything.

0 Kudos
Message 4 of 15
(1,672 Views)

Instrument 1 - A QMH which on initialization tells the display manager actor to launch X display windows with such and such settings.   When the user "saves" the settings for Instrument 1, the instrument needs to query the display manager for the current settings.  On Exit it does a last query for the display settings and saves them to disk with it's other settings until the instrument is launched again.

 

Instrument 2, 3, 4, ... - Other instances of the QMH 

 

Display - An Actor or QMH (different displays are Actors or QMH's depending on when they were refactored last) which contains its own state and which the user can interact with to change how the display presents data and even what data is presents.   Has it's own block call mechanism which it uses to respond to the display manager when queried for its settings 

 

Display Manager Actor - An entity which receives messages to open and close Displays, does so, and keeps track of their enquers or other communication mechanisms (queues in the case of QMH's).   Receives blocking requests to get settings from open Displays, then it in turn sends a blocking request to each display for their settings, Bundles all this information up and returns it to the requester (i.e. Instrument 1, 2, 3 ...  in this scenario).

0 Kudos
Message 5 of 15
(1,658 Views)

@Thomas_robertson wrote:

The problem is how to get information from the display manager such as number of open displays, settings, and such.   From the readings it sounds like every entity is supposed to send query messages up a tree, and some root actor eventually repeats them down to the display manager, which in turn then sends the information up the tree, and it gets repeated back down to the entity that wanted to know.   But all the while, the code that needs to know that can't be sitting there waiting for it, instead is has to just stop what it's doing and go idle until the message with the display settings comes in, then it needs to return to where it was when it needed the information and start using it.    That sounds crazy complicated.


Transitioning an actor to an idle state is how it should work if you want your actor to remain responsive to other messages. I have a few Actor based applications that collect a lot of user input during use.

  • The UI actor and process actor are separate entities
  • The user input needs to be collecting during the process, and the process cannot proceed without it

Given those facts, the use case sounds similar to yours. My application can wait indefinitely for user input, so I absolutely want to avoid synchronous messaging that would result in blocking the process actors. I think of my process actors as state machines where each step in the process is a separate state. They hum along doing automated work until it's time to request user input. The process actor sends a message to the UI actor requesting the user input, then it transitions into an idle state. This allows the process actor to handle other incoming messages (i.e. Cancel the current sequence or Shutdown the application) while waiting on the user input. The UI eventually sends a response message to the process actor, and the process actor transitions out of the idle state to the next step in the process.

 

There are a few options for how to exchange messages between actors that don't have a direct parent-child relationship - each has it's own pro/con list. Like you described, you can adhere strictly to the tree structure and pass messages up and down the tree, but the amount of boilerplate code for message forwarding can quickly become cumbersome. You could eliminate some of the forwarding code by including the sending actor's enqueuer as part of the request message. When the UI actor sends the response, it has a direct link to the requestor effectively short circuiting the return path. Finally, like  suggested, you can treat your UI as a shared resource that's directly accessible everywhere by sharing the UI enqueuer with each actor (that needs it) in your application. Each process actor can send messages directly to the UI and includes it's own enqueuer as part of the message so that the UI can send responses to the correct place. The last option is the one I typically use. Each request for user input has a unique response message so the process actor always knows which piece of user input is being returned and can resume whichever sequence was idling.

Message 6 of 15
(1,647 Views)

@Thomas_robertson wrote:

Really?  It's considered ok to make block calls to Actors as long as those Actors aren't making calls back to you?   That's considered acceptable design?   This is the first time I've read such a thing, I thought everything I've read was clear that block calls are always and forever a code smell that should be eliminated.


I don't think he meant blocking calls to Actors, just blocking calls to a shared resource.

 

Does the manager need to be an Actor, or can it just be a by-ref Object? If you have a regular ol' by-ref singleton object* then you can distribute it to everything that needs it. It sounds like you might not need this display manager to actually send and receive messages.

 

Or, you could still have your display manager send and receive messages, but it operates on a by-ref "Display storage object" that's shared among your other Actors.

 

*Singletons and by-ref objects aren't the normal paradigm in LabVIEW. Normally, you use by-value objects, meaning when you create one and split the wire, now you have two. With a by-ref object, you instantiate it once using a DVR (for example) to hold the data. Then when you split the wire, you're duplicating the reference instead of the data. Then everything that needs to operate on the object itself can use blocking calls on your shared resource. This is the way that lots of shared resources are handled (e.g., serial ports using VISA)

Message 7 of 15
(1,625 Views)

The simple answer is despite what "some" of the AF (and DQMH) evangelists may tell you, not everything needs to be asynchronous.

I often see DQMH modules where every Request is a  Request and Wait For Reply. If that is the case and everything is synchronous, then it shouldn't be a DQMH module or AF actor.

 


@Thomas_robertson wrote:

Our code is a large set of synchronous code mixed with an increasing amount of Actors (most of which are just front ends wrapping old existing synchronous code), that probably has a big effect on how I think.

Just because asynchronous actor-oriented programming is the latest shiny tool, doesn't mean it solves all problems. Not everything is a nail, even when you have a really great hammer.

 

It sounds like perhaps your display manager should just be a simple functional global variable or action engine that all your displays depend on....

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 8 of 15
(1,609 Views)

Going back to the original question, switching to an asynchronous mindset definitely takes some getting used to, but once you get used to it, I find it's actually a lot more natural and analogous to the "real-world".

 

Imagine I'm an actor. I can do one thing at a time, serially (I'd argue that people who say they're multitasking are really just switching single tasks rapidly, but that's a different story). Say I need to mow the lawn, take out the garbage and then run to the store to get some groceries for dinner, so I start mowing the lawn. Pretty soon I realize that while I know most of what I need from the store, I don't know if we're low on milk. So when I'm done mowing the lawn I shoot a text to my wife asking her to check if we have enough milk. But while I'm waiting for her response, I don't stop doing whatever else I need to do. I continue with taking out the garbage and when that's done, I get in the car and start driving to the store. When my wife messages me back telling me whether or not we're good with milk I take the appropriate action - get more milk or don't worry about it, but I haven't stopped doing my other tasks in the meantime.

 

If messaging my wife had been done serially, I would have stopped doing anything after mowing the lawn and I'd wait for her response before moving onto any other task. It's much more efficient (and natural, IMO) to do things asynchronously.

 

Does that make sense?

 

If the concern is the overhead of sending messages up and down the tree and creating a bunch of repeated or boilerplate code it might be worth looking at redesigning your actor launch tree or consider compositing the resource into your other actors as others have suggested. If you've done that and still would be sending messages across several actor nodes (e.g. GUIs with lots of other GUI actor components nested within each other) then you might want to look at something like this to ease the pain.

CLA CLED AF Guild
0 Kudos
Message 9 of 15
(1,607 Views)

@Thomas_robertson wrote:

Really?  It's considered ok to make block calls to Actors as long as those Actors aren't making calls back to you?   That's considered acceptable design?   This is the first time I've read such a thing, I thought everything I've read was clear that block calls are always and forever a code smell that should be eliminated.


don't listen to the zealots...

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 10 of 15
(1,606 Views)