Before I get into the answers, I first want to mention that we often don’t document implementation details for Roblox systems as we don’t want you relying on implementation details that might change over time.
Having said that I think that providing some more details about the actor system will help answer your specific questions. But per the above, please keep in mind that the details could change over time.
The client and server both have threads that are able to run parallel luau scripts. The number of threads depends on the system running the engine and various other factors. However, it is often the case that there will be more actors than OS level threads available to run them. For example you might only have four OS threads but 16 actors. The work for each actor is assigned to a task, and those tasks are dynamically scheduled across the four OS threads.
All the scripts under an Actor will be part of the same task and therefore they will all run on the same OS thread. That way the scripts for an Actor won’t interfere with one another (e.g. they can’t create race conditions amongst themselves). This is important because all the scripts under an Actor run on the same Luau VM. And a Luau VM can’t execute on multiple OS threads at the same time. (Note: in some cases multiple Actors may also share a single Luau VM. So you shouldn’t assume that each Actor has its own Luau VM.)
We considered traditional thread communication mechanisms when designing Parallel Luau. A lot of mechanisms that developers coming from C/C++ may be familiar with are not necessarily a good fit for Luau. For example:
- because parallelism is achieved using multiple Luau VM’s it is hard to share data between them. Native luau tables don’t support parallel access at all and are always owned by a particular VM.
- in the same way that Luau provides a memory safe environment for developers, we also wanted a parallel programming model that prevented certain classes of threaded programming errors from occurring, such as deadlocks due to incorrect usage of locks or semaphores.
Using message passing and special data types (i.e. SharedTable’s) were the mechanisms we decided to provide. We realize that could mean some types of communication are more difficult or less efficient. But the model used provides safety guarantees and future flexibility that are important to us.
Of course, we are willing to consider other additions and mechanisms as long as they provide the safety guarantees we want and fit with the overall programming style/model of Parallel Luau.
Within Roblox, scripts can run either serially, or in parallel with each other. A call to synchronize or desynchronize effectively suspends the execution of the currently executing Luau thread and places it in a queue to be executed later. More specifically, calling synchronize will pause the Luau thread and cause it to resume at the next serial execution phase and calling desynchronize will pause the Luau thread and cause it to resume at the next parallel execution phase.
Scripts will often synchronize immediately before they write data or call a method that is not available to call in parallel. However, running as much code “desynchronized” as possible will maximize the ability for scripts to run in parallel with one another.
For completeness I’ll also mention that sometimes scripts begin executing in serial or parallel for other reasons. For example if you “Connect” to a signal then the signal handler will run in serial. However if you “ConnectParallel” to a signal then the signal handler will run in parallel with other scripts.
Lastly, your question was excellent as it has highlighted where we could improve our documentation. Look for updates soon that echo the above in our official documentation here.