Insufficient documentation about actors

I have some questions about Actors that’s not really answered in the documentation. I would like to get in touch with a software engineer to gain some clarity about this.

  1. Does the scripts that are under actors actually run in separate threads? When I say thread, I mean like a pthread type thread which runs on a different CPU or CPU core than the main thread.

  2. Interthread communications is a pain to deal with. To get data back (like a function returning a result) I’ve had to resort to using bindable functions. To send data one way, I use the API which is Actor:SendMessage(). It seems to work, but the limitations of data types (especially with tables), makes this messy. A shared table doesn’t really work for this. Is there another way to accomplish this?

  3. What does task.synchronize() and task.desynchronize() really do with the code? What do they synchronize/desynchronize with? In a C/C++ environment, I understand what happens when I issue pthread.create(). That forks off a new thread in the process which has the ability to run in parallel on a different CPU/CPU core. To guarantee exclusive access to a shared resource, I use mutexes which are basically spinlocks. There are also read/write locks, and other types of synchronization functions as well. As for parallel LUAU, I don’t quite follow what these methods do exactly.

On a personal note, I’m a system software engineer myself. I write operating system software which includes kernels, device drivers, libraries for APIs, system boot code that get’s burned into ROM chips…the really low level stuff. So I’m requesting a technical explanation at the same level. The “overview” in the documentation I’m having a hard time grasping.

4 Likes

We’ve filed a ticket into our internal database for this issue, and will come back as soon as we have updates!

Thanks for flagging!

2 Likes

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.

Q1

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.)

Q2

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.

Q3

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.

3 Likes

First of all, excellent response. I understand that implementations will change over time to fit the current needs of the engine and the features that it supports. I have found that using bindable functions to get data back from across actor boundaries, but they can only be called in serial because they block the thread until the function returns.

So threads within an actor always run series with each other per the original engine threading model. But threads between actors can run in parallel, if I’m correctly understanding what you are saying. With that, I am assuming that when a thread in an actor calls task.synchronize, it merge’s the actor’s run list with the main thread’s run list (I define the main thread to be the one that is not part of any actor.) while task.desynchronize does the opposite: It takes all the actor’s threads (tasks) out of the main thread’s run list and places them in a separate OS thread.

Is that correct?

If so, that clears up quite a bit of confusion about Parallel LUA since another language that I’m familiar with (PHP) does something similar. In that language, each thread runs in it’s own VM with it’s own copy of the JIT compiler. The drawback is that there is no easy way to perform communications between threads.

So threads within an actor always run series with each other per the original engine threading model. But threads between actors can run in parallel, if I’m correctly understanding what you are saying. With that, I am assuming that when a thread in an actor calls task.synchronize , it merge’s the actor’s run list with the main thread’s run list (I define the main thread to be the one that is not part of any actor.) while task.desynchronize does the opposite: It takes all the actor’s threads (tasks) out of the main thread’s run list and places them in a separate OS thread.

The way it works is similar to what you described, but not exactly the same. task.synchronize() and task.desynchronize() only affects that Luau thread making the call. So instead of impacting all the Luau threads belonging to an Actor, it only affects the ones that call the API. It is quite possible for some Luau threads from an Actor to be running in serial and other to be running in parallel.

You are correct that threads associated with different actors run in parallel. e.g. threads from Actor A can run in parallel with threads from Actor B.

Now I understand. That cleared up a lot of confusion as to what was going on.

Thank you for responding and answering my questions.

Cheers.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.