As a Roblox developer, it is currently too hard to fully utilize Actors and parallel processing in game creation. The inability of Actors to modify the data model without synchronizing really limits their usability.
If possible, it would be nice to either:
Similar to BasePart:SetNetworkOwnership(), add an Instance and its descendants to the “Actor” even though they’re not in the same hierarchy, and that Actor has write access on the object.
Allow for potentially unsafe reads and writes for an actor given the creator “opts in” to it
If Roblox is able to address this issue, it would improve my development experience because games would be able to execute a lot more code in parallel vs. just with threads. Some use cases of this are:
Adding a special Gui to each player’s head that is set / animated client-side
Animating a lot of projectiles at once
Camera manipulation work placing instances inside the Camera / Workspace
Basically, self-contained tasks that require write access to usually an instance or two, when that instance generally isn’t written to or even read outside of the one script.
Please I need this!!! You do not understand how much this would help my work, I use 3d part based effects and while I can have about 1000 running at 60fps stably in perfect conditions I really need to be able to do this task in Parallel. If I could disperse the load across many threads it would be a massive performance boost! That’s just the tip of the iceberg! Actors could animate themselves if set up correctly, as I use procedural animation for almost everything I do, this could improve the performance of so many things, making each object animated in Parallel. I have been wanting something like this since Parallel Lua was announced! As it stands Parallel Lua is heavily held back by harsh restrictions, this makes it pretty much useless to the average user. With this feature more developers could actually take advantage of Parallel Lua! I’m sure some roblox core scripts could as well for more performance!
I can think of 1000000 ways to use this, and would use it constantly, please consider adding something like this, where an actor can take control of instances. Even if those instances are read/write locked to every other script in game, this would still be super useful!!! Self contained scripts that change instances only they mess with are pretty common depending on what you are doing, and this would be a MASSIVE boost performance wise to this kind of tasks.
This would be awesome! Many times I have been unable to properly parallelise a script / algorithm because I can’t change the data model at all. The ability to take thread ownership of a part to prevent race conditions / multithreaded bugs would be an amazing change to allow for fully parallel luau!
It’s completely crazy to me how, in the developer documentation for Parallel Luau, we have “Local Safe” listed as an option, yet not a single property or function call in the entire engine is marked or usable in this fashion.
I can only assume it’s because this behavior hasn’t been implemented yet, rather than Roblox just “forgetting” about it, but still, it’s really really annoying that this is an issue at all given how many use-cases would be made better with it.
I want unsafe parallel code.
Multi-threading in Roblox is currently almost useless for things that need real-time or every-frame parallel logic.
I recently learned that communicating between actors is extremely slow.
Using bindable events or functions is also super slow.
I want to be able to simulate tons of projectiles efficiently but this requires being able to read/write data every single frame and being able to retrieve data from anything that was hit by a projectile.
The whole multi-threading system is completely flawed and limited, likely because it only allows safe/secure read and write operations which makes data and memory sharing super slow.
This is pedantic but in reality this would just be shifting the responsibility onto the Engine to collect all the property changes and apply them serially. “Unsafe parallel code” is nonsensical here.
How would that require the engine to apply property changes serially? There is no programmatic limitation with writing to memory in parallel, we have the Task Scheduler for a reason, which will not continue to the next task/frame until the current task is complete, and that includes actor code (This is why parallel execution can stall frames). So the physics engine, for instance, literally can’t be affected by this.
The only thing that can potentially be impacted is the state of memory if another thread wants to access it during that same task (as is the case with any multithreaded code), which isn’t a concern for cases where - for instance - a part will only be accessed by a single actor.
This whole thread is just developers who don’t understand why things are in place, thinking that ‘solving’ this issue would improve performance.
By doing something like this, you’re likely to make the client more unstable, just for a ‘bit’ of performance. Quite honestly cope with it; making and introducing potential crashes is something that I bet ROBLOX would never do unless they were clinically insane, quite honestly.
There is a reason why synchronization is needed. It isn’t ‘optional’.
This is incorrect, doing the bare minimum for multithreading would not introduce potential crashes. If an actor could assign an instance to itself (Using Roblox’s own definition of “Local Safe”) wherein no other thread can modify that instance, then it is literally impossible for this configuration to result in any kind of instability (so long as it’s implemented properly by Roblox themselves). In fact - this exact pattern I’ve described is an accepted standard practice for many, many use cases in game development.
Also - the (potential) performance improvements from this would be quite large. Roblox is very frequently CPU limited, both on the client and more commonly on the server side. Being able to split workloads across multiple threads, especially on highly intensive procedures (such as pathfinding, which cannot be ran in parallel currently), would amount to huge performance gains when scalability is taken into account.
The design of the engine itself prevents this; even then, ‘bare minimum’ for multi threading on this style is still potential crashes. The engine legit simply cries if you resume a yielded luau thread at the wrong time in C/C++, same thing with other mechanisms, they cannot simply rewrite probably a quarter of the entire scripting backend for a feature that:
weakens the stability of the engine
introduces new challenges on the way things are structured
is an ‘expensive’ change due to it needing a rewrite and refactor of an existing, stable system.
doesn’t particularly guarantee the use of Parallel Luau aside from specific use cases
Parallel LuaU is still extremely specific. It would be like begging multi threading without Actor objects. You cannot, because LuaU becomes extremely unstable if you multi thread on a single Luau VM, which is why every actor represents a VM, which is why there are like three thousand locks inside of the engine; a change like this wouldn’t be easy and would require many changes internally from what I have seen while devving my own stuff.
It is a change that is not worth it, Parallel is very specific, and safety for writes cannot be guaranteed on virtually anything without a lock.
For such a niche thing, it is likely not worth modifying the engine code that much, other thing are likely to take priority.
Just because a Part can only be accessed by a single Actor, doesn’t mean that other threads can’t influence it. Simply creating a new Instance can cause data structures to run out of space and get re-allocated, moving all the memory and leaving any Actor which may have been in progress of writing to it with a memory corruption or access violation.
Also, I’m not entirely sure, but I was under the impression that Actors could be resumed throughout the entire frame, i.e. they can run parallel to rendering and physics, which presents even more opportunities for memory corruption if an Actor changes data while it’s being read by either in an “unsafe” system (but do correct me if I’m wrong).
At the end of the day, there is simply no way to avoid a synchronisation step in anything with state. There is only one source-of-truth, which must be able to communicate changes to everything, thus everything has to go through it at some point.
I’m not saying that having the Engine do this sort of synchronisation instead of us isn’t better or more performant, it would make a lot of our lives easier and I think it’s what Parallel Luau should eventually be. Actors maintaining divergent datamodel states and the Engine doing the synchronisation itself instead of us having to maintain the lists of property changes and serially applying them ourselves like with the example C_Corpze gave.
This step doesn’t happen, at least as far as I can find evidence for, during any of the Luau execution phases, and I don’t even think it could, since if it did, then two actors reading the same property, say CFrame of a part, which is read parallel (most if not all properties are read parallel) could get different results or a crash if this reallocation happened during execution. I’m more than open to feedback if I’m wrong or misunderstanding what you mean here.
They can not. You can attach a parallel execution phase to PreRender or PostSimulation or any other RunService connections, but the task scheduler won’t continue until those threads are done with their work, and they cannot (at least not by design) be resumed until an execution phase occurs, same as normal scripts.
Indeed, you are correct here, but there is a solution to accessing state in a semi-multithreaded context, and that is mutexes. The engine could place a mutex on the properties of an instance that “belongs” to an actor, and thus would not allow any other threads to modify that instance. We can then lift this mutex when the Luau execution phase ends. (So that way the core of the engine can access that data if it’s needed, like doing physics sim on parts.) This way we can do work on instances in a multi-threaded context, just that a single instance will only be accessible from one thread at a time. Mutexes/Locks are common for stuff like this and I don’t see any reason why it wouldn’t be implementable in Luau.
Roblox is aware of this and they themselves have talked about this type of thread safety in the documentation as something that will likely be coming to the engine eventually, it’s just not implemented at this time, and in hindsight, I was being a little bit arrogant in my original post. Because yes, this is not a trivial change at all and would be a somewhat significant overhaul to the engine - but I don’t think that’s any reason to write this off completely especially given that it does have value as a feature.
I wouldn’t suggest a lock if I hadn’t used them before, their performance is the subject of a lot of confusion and misjudgment, but to make a long story short, it depends a lot on what you’re doing, and in this case the mutexes would have a negligible performance penalty, especially when considering the extra work that could be done.
The cases where mutexes become slow are when memory becomes contested and the frequency of the mutexes is very high, but the design that has been proposed here (using a function to explicitly define an instance as part of one actor and no other actors) inherently prevents contention between threads, and the duration of the mutex would be relatively long. So in this case, the mutexes would be very cheap. Of course, if we want to write to the same instance properties across many threads simultaneously, then it becomes not-cheap, but that’s not what the feature request is proposing here.
I think it’s quite bold to assume that you are correct and fully understand the engine. Also, to go against an idea simply because you think it wouldn’t work or it doesn’t benefit you is quite silly.
This could be extremely useful to developers, especially if they know what they are doing. Roblox has always been CPU bottlenecked for me (Client and Server) and I would love to have the tools to get more out of the CPU. Things like visual effects, projectiles, animations (with code), and more cause alot of CPU load. These tasks are usually stand alone tasks that only 1 script controls. Being able to split tasks like this onto separate threads would free the main thread to do other work This would improve performance on almost any device.
Even phones now-a-days have at least a few CPU cores. The IPhone 5 (released in 2012) has 2 cores, even this could boost performance in experiences that took advantage of this feature request.
Keep in mind that this argument is invalidated when you realize that the games that introduce buggy and unstable Parallel Lua will suffer as a result, not ROBLOX itself. It’s up to the developer to use Parallel Lua responsibly, as with every other feature ROBLOX has provided. A while true do loop that spams instance creation makes the client unstable and crash, right? We can still do that. Why not apply a similar thought process to Parallel Lua?
Because that could allow arbitrary memory attacks for malicious bad actors, like reading the player’s credentials, or modifying memory in such a way to even result in low-level Arbitrary Code Execution. It’s a sandbox escape in an architecture that assumes it’s impossible, Luau is supposed to have important safety guarantees that Roblox can’t just forego.
Not to mention, how can anyone here begin to imply that Parallel Luau, without these safety measures, is even stable enough to be usable? These are implemented because of stability issues, not because they just felt like it.
Arbitrary memory attacks for malicious bad actors. That’s what you say can happen if we prevent Actors from just manipulating instances in the DataModel?
Are you absolutely sure? Take into consideration that Roblox and it’s Lua engine has existed since it released in 2006 and there have been zero clientside vulnerabilities in its VM that could ever lead to remote code execution that could’ve been planted by a developer. The only sandbox escapes I’ve ever seen were from developers messing with flawed exploits…
Unsafe Parallel Lua would create Roblox’s first RCE vulnerability?
Rely on the “It never happened before, therefore it won’t happen” type argument isn’t a good thing.
Any crash or memory corruption is bad. Regardless of anything, engineers shouldn’t waste their time integrating the bugs they very much remove.
It is as if you unlocked the main door of your house in a bad neighborhood at night, something may happen, not for sure, but may, and just because it may, it is simply easier to lock the problem away.