Originally I was thinking a gateway timer script have it it run there. But this brought 2 potential issues.
Without knowing exactly how long each script can run or taking into account any factors that can delay the code execution time. Lets say I set the timer to execute every 2 seconds and my code finishes executing in 2.1 seconds. Now we have 2 scripts running.
Assuming we handled the above issue with a check to see if the script is running. The script finishes in 2.1 seconds. But at 2 second mark the timer see that it was running so it does not execute. Now between 2.1 and 4 seconds, no scripts are running.
Each of the 10 scripts we cannot give a set time for as we do not know how long each script can potentially run for.
Kevin's approach is the safest, not using invokeAsynchronous(), and you need to make sure your scripts stop regularly, so that project edits will replace the code.
It's important to understand that gateway startup scripts are not just gateway startup - they are also any time the project is saved and the scripting gets reloaded. This makes for a very difficult to manage lifecycle when you're trying to do everything yourself in the background like this.
where it describes fixed delay vs fixed rate. In neither case will the same script be overlapping in execution.
In "Fixed Delay", your script runs again at whatever the interval is after the execution finishes.
In "Fixed Rate", your script runs at the fixed interval, but if an execution goes long it does not overlap, the next execution just begins immediately after the previous finishes.
These threads are running code logic which performs calculations real time. These calculations can affect tags which other scripts running on other threads will require.
So, like a PLC task? Just run them from gateway timer events at a fast fixed pace, each function being treated as if it were in a PLC.
The function would do the equivalent of one PLC scan's work and return. Set the timer rate appropriately for your application. Follow best practices for multi-threading in PLCs:
Use a single system.tag.readBlocking() at the beginning to gather all of the tag values your logic needs into local variables in the function.
Perform all of your logic, yielding new "output" values in function local variables.
Use a single system.tag.writeBlocking() at the end to send all of the new output values to their actual tags.