08-20-2021 05:16 PM
I feel like I'm painfully close to understanding this...let's say that I need to have Actor A change the current in the lightbulb N times, and then at each of the N currents measure the photodiode managed by actor B. This is a synchronous task. ABABAB...until AB has repeated N times.
With synchronous reply messaging, I could just put the sync reply A wired into sync reply B in a loop and do it N times. This would lock root until all N are done.
With asynchronous reply messaging would it go something like this? Root knows it wants to take N measurements, so its in a mode where it fires an async reply to A to change the current. When it receives A's async reply later with the new current, it uses A's async reply msg to fire off an async reply message to B. When B's async measurement comes back, it uses that reply to go to A...and so on until the N measuremetn pairs are done. After collecting N pairs, then it changes state to idle.
Am I starting to understand how to achieve synchronous behavior using asynchronous messages? I could be wildly off base...
08-21-2021 04:25 AM
Note that you can mix sync and Async. If you have an M-step process to do N times, you can do the M steps synchronously except for the last step. This will be a lot clearer, especially if M grows larger than 2 as in your simple example.
Also, I note that your "root/GUI" actor is doing two different jobs. Three, actually: the Manager of subactors, the Sequencer, and the GUI. If you separated these roles into more focused subactors, things might be easier, since your main problem is that sequencing things works well synchronously while your GUI needs to be Asynchronous.
08-21-2021 11:43 AM
You have the idea, but let me clean up your language to make the point a little more clear:
@WavePacket wrote:
With asynchronous
replymessaging would it go something like this? Root knows it wants to take N measurements, so its in a mode where itfires an async replysends a message to A to change the current. Whenit receives A's async replyA sends a message later with the new current,it uses A's async reply msg to fire off an async replyRoot responds to that by sending a message to B. When B's async measurement comes back,it uses that reply to goRoot responds to that message by sending a message to A...and so on until the N measuremetn pairs are done. After collecting N pairs, then it changes state to idle.
There are no replies (or commands). There are requests and announcements, and I prefer announcements. I apologize for being pedantic, but I find being precise about the language helps a lot with my thinking.
So does drawing out a sequence diagram with all your anticipated interactions between Root, A, and B.
Root knows everything about sequencing, and Root can be as synchronous as you need it to be, internally. What we're trying to avoid is having that sequence bleed out into A and B.
As an aside, if you don't want to use state pattern actors, you could likely build some kind of sequence object into Root that lets you script Root's responses. You'd likely still wind up with state pattern, but built in way you find more palatable.
08-21-2021 11:44 AM
@drjdpowell wrote:
Also, I note that your "root/GUI" actor is doing two different jobs. Three, actually: the Manager of subactors, the Sequencer, and the GUI. If you separated these roles into more focused subactors, things might be easier, since your main problem is that sequencing things works well synchronously while your GUI needs to be Asynchronous.
Truth. An actor should have one job.
(That way, when it fails, you can yell "you had one job!")
08-23-2021 07:59 AM
Hi Dr. Powell,
I realize that I've asked a lot of questions, and I've already learned a lot. I'm not sure I yet grasp what your last message was meant to tell me though. Mind if I poke a bit?
@drjdpowell wrote:
Note that you can mix sync and Async. If you have an M-step process to do N times, you can do the M steps synchronously except for the last step. This will be a lot clearer, especially if M grows larger than 2 as in your simple example.
...
I didn't understand why the last step can be async? Isn't the first step of the M-step process waiting for the last step to finish? (Well, except for the last of the M steps of the very last of the N iterations, I suppose.) If I'm honest, I also don't know why this is especially of aid when M grows large.
@drjdpowell wrote:
...
Also, I note that your "root/GUI" actor is doing two different jobs. Three, actually: the Manager of subactors, the Sequencer, and the GUI. If you separated these roles into more focused subactors, things might be easier, since your main problem is that sequencing things works well synchronously while your GUI needs to be Asynchronous.
Mind sharing a few words about how the manager of subactors differs from the sequencer? At first site to me as I learn this, sequencing the steps of the subactors seems just to be one job of the manager of the subactors.
Thanks again,
-Wavepacket
08-23-2021 08:20 AM
@justACS wrote:
You have the idea, but let me clean up your language to make the point a little more clear:
@WavePacket wrote:
With asynchronous
replymessaging would it go something like this? Root knows it wants to take N measurements, so its in a mode where itfires an async replysends a message to A to change the current. Whenit receives A's async replyA sends a message later with the new current,it uses A's async reply msg to fire off an async replyRoot responds to that by sending a message to B. When B's async measurement comes back,it uses that reply to goRoot responds to that message by sending a message to A...and so on until the N measuremetn pairs are done. After collecting N pairs, then it changes state to idle.
There are no replies (or commands). There are requests and announcements, and I prefer announcements. I apologize for being pedantic, but I find being precise about the language helps a lot with my thinking.
...
No worries about pedantic, it's helping.
I'm wondering for the quoted section if we actually describing the same thing, just using different language. How I was using "async reply" was that in as a part of A receiving the message, it also sends a message to root a message that it's finished. Here, we aren't using the send and wait for response vi. ("Sync reply" was how I was trying to describe a reply message which uses send and wait for response vi.)
Perhaps you were describing a different scheme, which is that A is always announcing its current current. Root requests a change in current, and then detects when A's broadcast changes to the new current? Not sure if we are on the same page here yet, though I think we're now in the same chapter at-least ;D.
@justACS wrote:
You have the idea, but let me clean up your language to make the point a little more clear:
@WavePacket wrote:
...
...
As an aside, if you don't want to use state pattern actors, you could likely build some kind of sequence object into Root that lets you script Root's responses. You'd likely still wind up with state pattern, but built in way you find more palatable.
I'm not really opposed to using state pattern actors if they are the solution to this issue, I guess I feel like right now that I'm treading water right now just with messaging in AF in general.
08-23-2021 11:10 AM
You can do some "sorta-sync" messages too. As one option, you could send actor B a regular message with payload containing a queue and an interface or abstract message. When B takes its measurement, it will send that measurement back on the specified queue. This is sort of like a synchronous message, but actor A now can do whatever it wants until actor B's message comes back. Since A is describing a message that will later be sent to itself, it can create that message with all of the "next step", "next state", etc stuff built in. The difference is that actor A doesn't simply lock up waiting on the new message. You do have to maintain state in A with this paradigm though and can't do a simple loop like you would otherwise.
If you've used Time Delayed Send Message this will be familiar. With TDSM, you specify a message to send to a particular actor (it could be itself or it could be another actor). TDSM then launches a background process that either sends that message n times after a delay, or indefinitely until stopped, etc. It's a great metronome tool for repeated tasks and I like it better than a helper loop.
TDSM sends the message after a certain time is elapsed. With my method above, the message is sent when a new bit of data is obtained.
Of course, I admit you lose some functionality, like timeouts, going this route, but you avoid the synchronous message issues too.
08-24-2021 10:53 AM
@WavePacket wrote:
Hi Dr. Powell,
I realize that I've asked a lot of questions, and I've already learned a lot. I'm not sure I yet grasp what your last message was meant to tell me though. Mind if I poke a bit?
@drjdpowell wrote:
Note that you can mix sync and Async. If you have an M-step process to do N times, you can do the M steps synchronously except for the last step. This will be a lot clearer, especially if M grows larger than 2 as in your simple example.
...
I didn't understand why the last step can be async? Isn't the first step of the M-step process waiting for the last step to finish?
I mean you don't have to do every step by Asynchronous replies. Synchronous waiting for reply, because it is just like calling a subvi, has a lot of advantages, such as in readability. By making one step an asynchronous reply, you give the actor a chance to handle other messages. Doesn't have to be the last step.
08-24-2021 11:02 AM
@drjdpowell wrote:
...
Also, I note that your "root/GUI" actor is doing two different jobs. Three, actually: the Manager of subactors, the Sequencer, and the GUI. If you separated these roles into more focused subactors, things might be easier, since your main problem is that sequencing things works well synchronously while your GUI needs to be Asynchronous.
Mind sharing a few words about how the manager of subactors differs from the sequencer? At first site to me as I learn this, sequencing the steps of the subactors seems just to be one job of the manager of the subactors.
Managers delegate. You could delegate the sequencing role to a specialized actor, one that can go though complex sequences without needing to fill any other roles the root actor may need to do.
08-24-2021 11:12 AM
@BertMcMahan wrote:
You can do some "sorta-sync" messages too. As one option, you could send actor B a regular message with payload containing a queue and an interface or abstract message. When B takes its measurement, it will send that measurement back on the specified queue. This is sort of like a synchronous message, but actor A now can do whatever it wants until actor B's message comes back. Since A is describing a message that will later be sent to itself, it can create that message with all of the "next step", "next state", etc stuff built in. The difference is that actor A doesn't simply lock up waiting on the new message. You do have to maintain state in A with this paradigm though and can't do a simple loop like you would otherwise.
If you've used Time Delayed Send Message this will be familiar. With TDSM, you specify a message to send to a particular actor (it could be itself or it could be another actor). TDSM then launches a background process that either sends that message n times after a delay, or indefinitely until stopped, etc. It's a great metronome tool for repeated tasks and I like it better than a helper loop.
TDSM sends the message after a certain time is elapsed. With my method above, the message is sent when a new bit of data is obtained.
Of course, I admit you lose some functionality, like timeouts, going this route, but you avoid the synchronous message issues too.
What you describe is what I call an "Asynchronous Request-Reply with Continuation" (the message A provides to send to itself represents the "continuation" of the action).
You can do this with a timeout, BTW, and there is a subvi to do that in Messenger Library. On timeout, one is sent a "Timed out" error message.