01-05-2022 10:28 AM
Hi guys,
I'm writing an actor where I'm offloading a long task to its helper loop. That task needs access to the values of the actor's current private data, and then the actor needs to change private data depending on the results of the long analysis and the current private data.
My understanding is that actors are by value classes maintained in a shift register of actor core. Therefore in an actor's helper loop, which I create, I shouldn't make a second shift register with the actor's class wire -- that would create a copy of the actor's private data with all the potential bugs associated.
My issue is, within the helper loop's event I need access to the up to date private data of the actor's class. Now I thought about sending copies of the actor's private data when the event fires, but that has concurrency issues (if multiple such events are fired, and the first one modifies the private data the subsequent events will be making decisions based on stale data since I sent copies).
Do I want to send a reference to the actor's private data to the helper loop? Is that an Ok design within AF? I'm a little hesitant of that solution b/c now I have two things which might modify the actor's private data but maybe since helper loops are within actor its still "encapsulation". Not really sure...
Solved! Go to Solution.
01-05-2022 10:40 AM
You send a message to the self enqueuer from the helper loop. The message tells the actor to do whatever the action is and update its state.
If the data should more properly be state of the helper loop, move those fields out of the actor and into the helper loop. When the actor receives a message that needs to modify those fields, send a message to the helper loop (queue or user event) to do the action and modify the fields.
The whole point is that there is a single point of truth and a single action performer for any bit of data.
01-05-2022 10:47 AM
@AristosQueue (NI) wrote:
You send a message to the self enqueuer from the helper loop. The message tells the actor to do whatever the action is and update its state.
If the data should more properly be state of the helper loop, move those fields out of the actor and into the helper loop. When the actor receives a message that needs to modify those fields, send a message to the helper loop (queue or user event) to do the action and modify the fields.
The whole point is that there is a single point of truth and a single action performer for any bit of data.
Interesting, so I've never considered having a separate state to maintain, that of the helper loop. I guess I was kind of gravitating towards actors are their own states so I should put everything in their private data. I guess I'm not seeing a downside to having long-task state data could go into the helper loop's shift register. Then periodically the helper loop fires off a message with the current state to the actor when the analysis finishes.
Huh. Thanks, I'll give that a whirl.
01-05-2022 11:57 AM
Quick follow up on timing within AF -- is the timing guaranteed by AF that root's helper loop is up and running before prelaunch init of nested actors?
(My potential worry right now is a race condition where if in prelaunch init of a nested actor, a message is sent to root, and if root chooses to direct it to a helper loop, that root's helper loop might not be up and running yet.)
01-05-2022 12:10 PM
You would have to code for it. One way would be to send a message to self-enqueuer that the helper loop is up; and use that to launch the nested actor.
01-05-2022 12:17 PM
@Dhakkan wrote:
You would have to code for it. One way would be to send a message to self-enqueuer that the helper loop is up; and use that to launch the nested actor.
Ok, thanks. I presume there are downsides to just running the error wire through the helper loop before launching nested? That feels juvenile for some reason haha.
01-05-2022 01:18 PM
@WavePacket wrote:
Quick follow up on timing within AF -- is the timing guaranteed by AF that root's helper loop is up and running before prelaunch init of nested actors?
No. In fact, the parent helper loops usually are not already running when nested launches unless the launch is done from inside the helper loops.
@WavePacket wrote:(My potential worry right now is a race condition where if in prelaunch init of a nested actor, a message is sent to root, and if root chooses to direct it to a helper loop, that root's helper loop might not be up and running yet.)
You don't have to worry about that. The communication channels are established even if the loops are not yet running, so the various "send" operations that you're wanting to do all succeed. The parent enqueuer is already established, and any link you create from parent Actor Core to helper loop will already be established by the time the parent receives the message.
TL;DR: this is a non-issue.
01-05-2022 01:26 PM
Messages are handled in Actor Core (or, more clearly, the Call Parent Method node in your new Actor's Actor Core). Launch Nested Actor also doesn't return until Pre launch init returns, so if you have Launch Nested wired in series before Actor Core then you KNOW that Actor Core won't handle the new message until AFTER your nested actor has finished launching. The helper loops may or may not be running yet (it depends on where you put them of course). Like AQ said though, you're definitely not going to lose a message.
01-05-2022 02:13 PM
@AristosQueue (NI) wrote:
@WavePacket wrote:
Quick follow up on timing within AF -- is the timing guaranteed by AF that root's helper loop is up and running before prelaunch init of nested actors?
No. In fact, the parent helper loops usually are not already running when nested launches unless the launch is done from inside the helper loops.
- If you run Launch Nested Actor serially with the parent loops, the loops definitely are not started (pre launch init finishes before Launch Nested Actor returns, which is why its error code is catchable in the caller directly).
- If you run them in parallel, then it is hit or miss which one starts first.
@WavePacket wrote:(My potential worry right now is a race condition where if in prelaunch init of a nested actor, a message is sent to root, and if root chooses to direct it to a helper loop, that root's helper loop might not be up and running yet.)
You don't have to worry about that. The communication channels are established even if the loops are not yet running, so the various "send" operations that you're wanting to do all succeed. The parent enqueuer is already established, and any link you create from parent Actor Core to helper loop will already be established by the time the parent receives the message.
TL;DR: this is a non-issue.
If I rephrase this to check my understanding, what you are saying is that:
1. root will receive the message from nested prelaunch init
2. root method fires a user event (for which an event structure in root's helper loop is dynamically registered for)
3. then potentially right way, or sometime later, when root's helper loop is up and running, that user event will be handled. No event is lost b/c the loop isn't running yet.
Am I understanding this right?
01-05-2022 02:16 PM
@BertMcMahan wrote:
Messages are handled in Actor Core (or, more clearly, the Call Parent Method node in your new Actor's Actor Core). Launch Nested Actor also doesn't return until Pre launch init returns, so if you have Launch Nested wired in series before Actor Core then you KNOW that Actor Core won't handle the new message until AFTER your nested actor has finished launching. The helper loops may or may not be running yet (it depends on where you put them of course). Like AQ said though, you're definitely not going to lose a message.
Just to sharpen my question, I'm not worried about losing a message. I'm worried about losing a user event that's fired by root but before root's helper loop, which has the event structure that's dynamically registered to handle the event, has begun to run yet.