Jump to content

Continuous Measurement and Logging, redone with “Messenging” Actors


Recommended Posts

I’m hoping to add some sample projects to my “Messenging” package, and I thought it would be easy and instructive to rework one of NI’s templates, “Continuous Measurement and Logging”, as it is already somewhat actor-like with three communicating modules.  Attached is a (back-saved for 2011) copy of the NI project, with my version included (run “Main.vi” for the original, “Main.lvclass:Actor.vi” for my version). 

 

 I kept the basic functionality the same, but couldn’t resist changing some of the UI (in the old code, “Main” controls the UI; in the new code, published state messages from the Acquisition and Logging Actors set the UI).

 

Continuous Measurment and Logging with Messenging.zip

post-18176-0-55113600-1385471922.png

 

 Any comments appreciated.   Is this example less clear than the NI original?  Why?  How could I improve it?

 

In particular, is code like this (the most complicated interaction, I think) understandable without heavy documentation?  It’s a “Start Logger, then Start Acquisition, then Unset the Busy Cursor” three-actor chain message:

post-18176-0-41257900-1385472396_thumb.p

I’m thinking of making a “Send Chain Message” subVI (that accepts arrays of addresses and message labels) to replace the above code.

 

— James

  • Like 1
Link to comment

In particular, is code like this (the most complicated interaction, I think) understandable without heavy documentation?  It’s a “Start Logger, then Start Acquisition, then Unset the Busy Cursor” three-actor chain message:

An alternate is below, using synchronous “queries”, where the subVI waits for the remote actor to reply to the command (we don’t care about the contents of the reply, just it’s existence).  

post-18176-0-11111600-1385474485.png

This seems a lot clearer.  It’s disadvantage is that the Main message-handling loop is blocked while the two subActors start up, but in this case that is no problem, as we are preventing the User from doing anything anyway with the Busy Cursor.

Link to comment
  • 3 weeks later...

I tested it and it works fine. One dependency was missing, but this is easy to solve: http://lavag.org/files/file/235-cyclic-table-probes/

 

Like neil, my time is limited right now and this is also not my specialty. I'll give my opinions anyways (notice, I had like 10min for this):

 

I think your code is much easier to extend (while maintaining readability that is) than the NI version, but the complexity is on a much higher level (Actor Framework, JKI State Machine, Messaging Library). Anyways, there is one thing bothering me regarding the coupling of your actors. An actor is defined by its messages. You could bypass that by sharing references or reference-like objects that allow direct access to actor-specific data or functions, thus eliminating the need to use any actor message furthermore.

 

If I understand your code correctly, the actor messaging system is bypassed by the the messaging library. Now would it make any difference if you call an asynchronous VI instead of the actors?

 

There has been a webcast about a big project that has been solved using the actor framework, but I can't recall the name or find it... It involved a flexible UI where some actors are bypassed, as well as sharing actor objects with realtime targets and network sharing. The presenter did a very good job to reason about the downside of some stuff they did.

Does somebody know which webcast I mean? (NI Week?)

 

I hope my explaination is understandable. Maybe some actor framework guru could give his opinions. Feel free to correct me.

Link to comment
I think your code is much easier to extend (while maintaining readability that is) than the NI version, but the complexity is on a much higher level (Actor Framework, JKI State Machine, Messaging Library).

Ah, a terminology problem then; this code actually has nothing to do with the Actor Framework.  Rather, both take the "actor" terminology is from the Actor Model, which is used by a large number of frameworks for many languages.

 

I used the JKI because that's the QMH template I've used for years.  Perhaps I should adapt the QMH used by the NI example.  I don't really like it because it's a "send messages to myself" style which I think is potentially problematic.  

 

Anyways, there is one thing bothering me regarding the coupling of your actors. An actor is defined by its messages. You could bypass that by sharing references or reference-like objects that allow direct access to actor-specific data or functions, thus eliminating the need to use any actor message furthermore.

You could share references, but the idea behind the Actor Model is that such sharing becomes more and more problematic as a program scales up in complexity.  

 

If I understand your code correctly, the actor messaging system is bypassed by the the messaging library. Now would it make any difference if you call an asynchronous VI instead of the actors?

My "actors" are actually nothing but single asynchronous VI's sitting behind a message receiving mechanism.  

 

There has been a webcast about a big project that has been solved using the actor framework, but I can't recall the name or find it... It involved a flexible UI where some actors are bypassed, as well as sharing actor objects with realtime targets and network sharing. The presenter did a very good job to reason about the downside of some stuff they did.

Does somebody know which webcast I mean? (NI Week?)

Was that by Allen Smith?  I saw his talk at the European CLA summit.  If I may criticise the Actor Framework, that is just too complicated.  Even bending the "actor" rules for the "flexible UI" is too complicated.  

Link to comment
Ah, a terminology problem then; this code actually has nothing to do with the Actor Framework.  Rather, both take the "actor" terminology is from the Actor Model, which is used by a large number of frameworks for many languages.

 

I may have got confused. So this is basically a different implementation of the actor model? The only one I've ever used up till now is the "Actor Framework" that is now also shipped with LabVIEW.

 

:frusty:http://lavag.org/files/file/220-messenging/ Never mind. Memo to myself: Actor Framework != Only possible way & RTFM.

 

I used the JKI because that's the QMH template I've used for years.  Perhaps I should adapt the QMH used by the NI example.  I don't really like it because it's a "send messages to myself" style which I think is potentially problematic.  

 

It's fine, I too often consider more advanced implementations over the ones which are "recommended". It is just harder to learn multiple specialized modules over a single one for beginner (like me for this one). The NI version does everything, using standard tools that are shipped with LabVIEW (even though it is far away from being "easy to understand for beginner"). I favor your implementation of asynchronous calls for scalability. The NI version is good, but 3 or 4 parallel loops in a single VI are to much for me to stay calm ( always trying to find a "better" solution :) ).

 

You could share references, but the idea behind the Actor Model is that such sharing becomes more and more problematic as a program scales up in complexity.  

 

My "actors" are actually nothing but single asynchronous VI's sitting behind a message receiving mechanism.  

 

I was trying to say the exact same thing, however my initial statement has become irrelevant for this matter. You are not bypassing actor messages with your message system, it's just a different implementation of the actor model. I was comparing apples with oranges and got confused about something that was missing... Thinking about it from the new point of view, your implementation might be less complex than the "Actor Framework" I was talking about earlier.

 

Was that by Allen Smith?  I saw his talk at the European CLA summit.  If I may criticise the Actor Framework, that is just too complicated.  Even bending the "actor" rules for the "flexible UI" is too complicated.  

 

The name sounds familiar and I think he is the one (big guy with full beard). It's too long ago for me to be sure though. I just remembered a warning about bypassing the actor messaging using any kind of secondary system, since that would eliminate the idea behind the actor framework model. But that was completely related to the "Actor Framework" and some crazy complex project (and yes, it was way to complicated).

 

Now I'm getting excited to try the Messaging package... So many things I want to know, but no time at all :unsure:

Link to comment
 I just remembered a warning about bypassing the actor messaging using any kind of secondary system, since that would eliminate the idea behind the actor framework model. 

A major goal of my "Messenging" system is to make passing messages between loops and asynchronous VIs easy; easy enough to NOT be tempted to bypass it with alternate systems.  I also hope to make the individual interacting components (actors or loops) simpler and more flexible by giving them a simple common method of providing information to other components.  

 

I'm concerned that the initial learning curve is obscuring that it's supposed to be easy.  Pick an actor template (there's three), copy it, open the one and only "Actor.vi" that defines the actor and add message-handling cases.  "Reply" to messages and publish info using "Notify".  Then drop your new actor in your main VI, "Launch" it, and "Send" it some messages.  Every step is actually quite simple. And it's scalable; make a few actors and hook them together with the "Register by Label" method (like the Acquisition and Logging actors are connected in the example).  One only has to create one VI per actor, and only the most basic of LVOOP familiarity is needed (basically, just don't be frightened of a LVOOP class constant).

Link to comment
James, can you post your Euro-CLA summit presentation slides? Trying to dive straight in with this example is too much for me to grok.

I posted it here.  Unfortunately, I feel in that presentation I spent too much time on the inner workings (some of which are complicated), rather than on the use of the API (which I hope is simpler).  

Link to comment
I posted it here.  Unfortunately, I feel in that presentation I spent too much time on the inner workings (some of which are complicated), rather than on the use of the API (which I hope is simpler).  

Thanks. I am trying to understand it from the inside, rather than just a black box, so those slides will be good I think.

 

In the course of getting to grips with things I will probably knock together some really simple examples teaching myself the API, if I end up with anything worthwhile I will upload.

Link to comment
  • 2 weeks later...

For discussion, here are shots of the “Debug Option”, where I’ve added some extra comments.  

 

First the “Debug Option Dialog” case in the Main actor:

post-18176-0-59330900-1389184075_thumb.p

 

This is an asynchronous action; the Main code continues while the dialog is displayed.  When the User dismisses the dialog (or the 30s timeout occurs) a message is sent in “reply”.  Here we are sending the result back to the Main actor, and are relabeling the reply as the command “Dialog::Start Debug Option” (the message contains the label of the button the User pushed).  Effectively, this is an asynchronous request-reply to the User.

 

The Main actor receives the “Dialog::Start Debug Option” message:

post-18176-0-57257500-1389184523_thumb.p

Note that because of the "two-queue" nature of the JKI “state machine”, this message cannot be received before all the initialization cases execute (this is a potential race condition in the original NI example).

 

Now the code triggered if the User clicked the “Yes” button, “Start Debug Option"):

post-18176-0-56086000-1389184739_thumb.p

Note how we drop the address of the Message Display actor!  We don't trace the actor wire outside of this case.  This violates the usual rule of always cleaning up references that you create.  But it also means we know exactly what this actor will do by just looking at this limited code section.  This messaging setup is thus "static", in the sense that once started it will continue until the Main actor stops (the Message Display actor is an "Autoshutdown Slave", meaning it automatically shuts down when the code that launched it goes idle).  We can, of course, choose to store the Message Display actor address in the shift register, and thus modifiy its interaction at a later point.  But personally, I think being able to drop the wire refering to something improves readability because one can see that something is not being modified elsewhere.

 

Note added later: of course, we don’t truly drop the Display actor’s address, as it is sent off in registration messages to the three other actors.  But in this form the address can only be used to send the specified published messages (in this case, all published messages, but with an added prefix), and there is no ability for the other actors to send an arbitrary message to the Display actor.  Thus we have fully specified the messaging interaction in the case that launches the Message Display.

 

The ability to create limited-use versions of an “address”, such as causing the addition of a prefix, or wrapping it in a registration message, is an important part of the philosophy of this framework.  And this is for code readability; if I pass a bare, unrestricted, address to another code module, I have to inspect that module to verify what that address is used for.  But if I pass a limited-use address, then I can be sure of how it might be used, and it greatly reduces that amount of code knowledge I have to fit in my poor brain at one time.

 

Finally, heres the Message Display debug window:

post-18176-0-90651900-1389185057.png

Good debug tools are critical in working with asynchronous communication.   There is also a custom probe that displays message history in a similar way.

 

Comments?

— James

Link to comment
  • 2 weeks later...

Another hint on the bonus question: To log all the data I collect, I took care to Start Acquisition only after Logger replies that it is started, and I Stop the logger only after Acquisition replies that it has stopped.  Yet the Message Display received the stop info published by the Logger first.  What happened?  

Link to comment
  • 1 month later...

Finally, heres the Message Display debug window:

attachicon.gifMessage Display debug window.png

Good debug tools are critical in working with asynchronous communication.   There is also a custom probe that displays message history in a similar way.

So like many other developers I have my own spin on the actor design.  Had yours been developed when I needed it I may have used it instead but that's besides the point.

 

With my actor implementation I have a actor dedicated to probing the other actors messages.  This can be opened by going to Help >> Debug Application >> Actor Probe from the application so it can debug messaging in an EXE.  

 

I have a few things I'd like to suggest that you can choose to do or not.  In my probe I have the option to allow the size of the history to be changeable.  It's not necessary but some times having too large a history can add unneeded extra memory but at the same time when debugging you want it to be larger.

 

I also added a Pause and Resume function because some times messages come in quickly and with a history size being limited I might want to pause and look at what happened while the application continues as normal.

 

Lastly I'd recommend some way to look at the actual data that is being sent.  I see you have something for this but for more complicated data structures I don't think you'll see the values.  I highly recommend the Variant Probe.  With this not only can I see the history of messages sent, I can also look at the actual data that is being sent with it.

 

All of these things combined have helped me troubeshoot multiple applications when deployed and behavior can be slightly different then in a development environment.  I do think having a DT between messages is a great idea and I may implement that in the future.

post-6627-0-52346800-1394725107_thumb.pn

  • Like 1
Link to comment

If I were to spend some more time on probes, the next thing I might do is adapt my SQLite-backed logger to handle messages.  That would give unlimited history with search functionality.  My current probes do have variable history, but only to the extent of resizing the probe window (so not if you need quite a long history).

 

I really should buildup the variant display to the level of Ton’s “Variant Probe”, but I find most “complicated data structures” in my code become objects, encapsulated against any probing.  

 

I also have a preference for small and simple probes, without a lot of controls that take up space or take time to configure, but a “pause” function does seem like a good idea.

 

I have debated adding “trace” functionality into the “Send” function itself (and “Reply” and “Launch Actor”).  Theoretically one could add lots of advanced features like tracing which message is in reply to which other message.  But this would be a lot of work, and I shy away from loading down the basic framework (I would like the basic messages and messengers to be usable without the higher-level “actor” design).  One can, as in this example, build up your own application trace window relatively easily, through having a message logging actor registered for all published information of your other processes.  And, being custom, it can also be targeted; showing only a subset of the more significant messages.

 

Thanks for the feedback.  Have you considered posting your actor design as an example for others?

 

— James

Link to comment
Have you considered posting your actor design as an example for others?

I have and I maybe optimistic, but I think the community would benefit from it.  It does have some quirks at the moment and you can shoot your self in the foot if you don't know the 2 or 3 rules when using it.  I think I can have checks for these rules in the design with some extra coding but I want to keep it lean so I'm not sure what I want to do.

 

The main benefit of what I have is the generation of actors, their methods, and even the basic project starting point is done through scripting invoked through the tools menu.  This can be done also to add new methods to existing actors and projects.

 

The main reason I haven't released it yet is it was developed on work time and it is used on several projects here.  I've recently approached management asking them if I can post parts of our internal reuse library externally, hoping to get more things like this out there.  They have yet to respond so I'm guessing they are ignoring my request.  If that changes I will try to release all I can.

Link to comment
  • 4 years later...

hello drdjpowell,

Thanks much for trying to enlighten people about LV Actor Framework through re-making user-friendly example of famous "Cont Measurement and Logging" sample project.  At some point, did you finish making your example in public?  I am a beginner of Actor Framework and would like to refer to it for my next starting point after Evaporate Cooler example.  

Thanks!

 

Osamu  (CLA/CLED/LV FPGA expert)

TRIONIX (NI partner in Japan)

Link to comment

Hi drjdpowell, 

Thanks for your reply.  Yes, I guess I knew what Actor means as a general computer science term (I took NI's AF training course), but I misunderstood that this thread is somehow related to Actor Framework.  Sorry for bothering this thread with my previous comment.   Thanks. 

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.