Does system.tag.writeAsync guarantee write order?

Currently I am finding that series of sequential system.tag.writeBlocking commands causes unfortunate stuttering within the vision client. I know there is system.tag.writeAsync, but I want to be 100% sure that they are being written sequentially.

To be very confident, I would want to know the answer to the following questions:

  1. Does system.tag.writeAsync respect the order of command at all -- if I call five of these in a row in the same script, can I be sure that the tags will be written in the requested order?
  2. Does it respect global requested order? If I have two scripts running concurrently, can I be confident that if script A calls writeAsync before script B that script A's write will go through before script B?
  3. How can I await this write in script? There are various circumstances under which I want to wait for that write to complete before I continue, but I really don't want to block the main UI thread. Python 2.7 doesn't have asyncio so I am not confident using any of the asyncio rules that I know. I already tried a global variable tied into the async callback, but this didn't work. Do I have to set up memory tags and use them as intermediaries?

Basically, I'm not sure if this async system is all in a single thread elsewhere or if they are able to race each other. Fingers crossed they are in a single thread! :crossed_fingers:

The only scenario where you are guaranteed any ordering is if you pass multiple tags/values into a single writeAsync call. You shouldn't make any ordering assumptions about any of the other scenarios you listed.

writeAsync takes a callback function. You continue doing work in the callback, and if that work involves touching Vision UI components you need to make sure to use system.util.invokeLater.

So how am I supposed to do something like the following without locking the UI? all of these tags are modbus registers on a PLC and there is latency from multiple factors:

write(reg_1, False) # shut off power
write(reg_2, 10) # set charging rate
write (reg_1, True) #reactivate power

while True:  
  if read(reg_3) > 98: # if fully charged
    write(reg_1, false) #shut off power
    write(reg_4, True) # do something interesting
    break
  wait(0.01)

write(reg_5, status_code)

Do I have to make a chain of callback functions and actually stuff all of my code inside of them? They can't communicate with the main thread very easily so at best this method would very annoying and difficult to organize.

Its good that I can queue a group of sequential writes in a single call, but how can I properly ensure that multiple writes are respectful of the ordering between them?

Maybe run this all blocking in a new thread you start using invokeAsynchronous. Especially since you have that nasty wait call in there.

Otherwise yes, you need to chain this in a bunch of callbacks or create some kind of state machine to run all of this.

https://docs.inductiveautomation.com/display/DOC81/system.util.invokeAsynchronous

2 Likes

Okay, thank you for the pointer. Ill try this and see what happens.

You can pop off the new thread and then disable a button or start a spinner or whatever to indicate work is being done, then at the end of that thread use invokeLater to touch the UI and indicate it's done. Or just let it happen in the background with no indication... whatever works.

1 Like

What happens when you call writeBlocking inside of a function that is called using invokeAsynchronous? Is it exactly the same as calling writeAsync, functionally the same, or something else?

So far adding a foo wrapper around my script and then calling system.util.invokeAsyncronous(foo) at the bottom seems to improve the situation but still run slower than I'd expect.

It's not the same, the whole function you pass to invokeAsynchronous is running in a new thread, but each of the writeBlocking calls is going to make a round trip to the gateway as it sends the write and waits for the result. Where possible, batching your writes so that you write to multiple tags in a single writeBlocking might improve the performance a bit. But because of your ordering requirements you need to do blocking writes. If you want A to happen before B then you need to wait for A to finish before doing B.

1 Like

If the client-gateway round trips are hurting the performance, you might also consider moving this logic to the gateway and triggering it from the client somehow - tag change, system.util.sendMessage or sendRequest, etc. Might be a little trickier to deal with feedback though.

Even then, because of the ordering requirements, you're still waiting on round trips to the PLC for each write.

1 Like

Ok, that is more or less what I expected. Ill try all of these options and see what works best.