Parallel Luau Developer Preview

… for those of you that have too much CPU power you can switch N in raytracer.rbxl script from 50 to 150 and enjoy a crisper image. Yes, the fact that we aren’t saturating all 12 [logical] cores here is unacceptable and we’ll work on ourselves, but part of the frame here is physics simulation and rendering and some of these systems aren’t internally threaded to the max yet :slight_smile:

85 Likes

This topic was automatically opened after 53 minutes.

So does this mean that state managers like Rodux are a no-go in parallel luau for now?

16 Likes

This looks super cool. I really like the way the actors and task systems function. The VM solution is especially nice for avoiding blowing up the memory consumption of this system, while still allowing for modules.

Is there documentation on the execution timing that parallel threads can execute on? I’m wondering what places it’s safe to push to parallel, and avoid a frame of lag. Specifically, are these acceptable entry points for input:

  1. Stepped
  2. Heartbeat
  3. RemoteEvent/RemoteFunction invocation stacks

Or does a parallel execution occur after every possible lua execution block? This would be especially useful, but could create lots of reentrance. For specifics, does this deadlock?

Additionally, I"m about to test this, but one question I had is if your code is hosted underneath the main thread, will task calls still error? In this case, the issue is basically writing thread-agnostic code that I just want to push into the parallel execution code. I’m assuming this is not the case.

Looking forward to more of this–looks like maybe this can scale Roblox across multiple servers, to create some truly massive experiences. I’m excited to see what this will bring!

27 Likes

This is so cool! (also, was that voxel terrain gen example aimed at me?)

Question tho: can you create instances in parallel if they’re outside the data model? It’d be cool if we could parallelise creating large numbers of instances (for science, of course!)

27 Likes

As predicted, I was 300% not using this right. Suppose that’s what I get for messing with features that don’t have any documentation!

I’m sort of struggling to come up with any projects that might actually benefit from being parallelized, but I think my serializer might be a good contender? A bunch of string manipulation in a loop seems like a good candidate anyway.

Also, finally, Roblox can run Doom at 60fps… What we’ve always wanted.

7 Likes

Ok, so it looks like the desynchronization time is something like 1/60

local startTime = os.clock()
while true do
	task.desynchronize()
	
	print("time to desync", os.clock() - startTime)
	startTime = os.clock()
	task.synchronize()
	
	print("time to resync", os.clock() - startTime)
end
  18:11:06.350  time to desync 0.016767400025856  -  Client  -  LocalScript:5
  18:11:06.350  time to resync 0.00017469999147579  -  Client  -  LocalScript:9
  18:11:06.369  time to desync 0.018455900019035  -  Client  -  LocalScript:5
  18:11:06.369  time to resync 9.8699994850904e-05  -  Client  -  LocalScript:9
  18:11:06.386  time to desync 0.016901900002267  -  Client  -  LocalScript:5
  18:11:06.386  time to resync 3.399996785447e-05  -  Client  -  LocalScript:9
  18:11:06.406  time to desync 0.020426300005056  -  Client  -  LocalScript:5
...

This is especially interesting, because it means that :ConnectParallel() is actually really important to avoid frame-delays. I’m assuming if we connect to inputs and other properties in parallel, maybe we avoid the frame-delay.

I think the way this is working, is it seems if you don’t have an actor, it still executes the stuff in parallel, but sort of parallel-under-a-global actor.

I’m going to see if BindableEvents/Functions operate as a safe interop boundary for this sort of thing. My guess is “yes”! I think if this is the case, we’ll start having a lot more interesting interop/source-of-truth designs coming up.

Super exciting stuff.

Edit: Looks like maybe ContextActionService is about to have a wrapper, there’s no way to connect something in parallel on it.

That being said, ContextActionService is pretty global, so I don’t think you can avoid syncronizing your thread from a global perspective.

19 Likes

This crosses VMs, right
Does the operation critically improve over a task where you might just mindlessly use a BindableEvent/Function and make a thread or should we be more cautious

2 Likes

Adding onto this, I would like to know what the expected design patterns will be for exchanging data from normal code to parallel code and between different parallel actors.

Since parallel code will require synchronizing before writing to the data model, how would this affect behavior such as BindableEvents being able to pass and receive functions created by different actors?

8 Likes

It looks like right now connecting to user input results in parallel results in 2 frames of input lag unless I’m misinterpreting these results. So responding to userinput will probably always be delayed by a frame if you need to do heavy computation with synchronious output.

  1. :Connect() event occurs normally
  2. RenderStepped occurs
  3. :Connect(), task.desynchronize() executes at the same time as :ConnectParallel(), but ConnectParallel() prevents a second closure from running synchronously, so that’s slightly better.
  4. RenderStepped occurs
  5. Synchronization of previously desynchronized code runs now.
  6. RenderStepped occurs.

Is there a chance we can get this reduced down to 1 frames of input lag? I’m not realy sure if I’m doing something wrong, or if this is intended.

While executing certain things (like gun raycasting and whatnot), are acceptable for a frame of lateness, it seems that any expensive interactions I’d want should not be delayed by effectively 33ms, which is way too much input lag in my opinion.

  18:26:13.517  Running synchronious (Parallel) 1607970372.6385  -  Client  -  LocalScript:12
  18:26:13.518  RenderStepped occured 1607970372.6397  -  Client  -  LocalScript:33
  18:26:13.522  Running parallel (task.desynchronize()) 1607970372.6432  -  Client  -  LocalScript:27
  18:26:13.522  Running parallel (ConnectParallel)  1607970372.6434  -  Client  -  LocalScript:7
  18:26:13.537  RenderStepped occured 1607970372.6587  -  Client  -  LocalScript:33
  18:26:13.539  Running synchronious (ConnectParallel, task.synchronize()) 1607970372.6602  -  Client  -  LocalScript:20
  18:26:13.551  RenderStepped occured 1607970372.6727  -  Client  -  LocalScript:33
10 Likes

This seems so amazing! Are there any use-cases where you would discourage the implementation of using Actors? Like in what instances could concurrency issues occur with this feature?

2 Likes

I believe right now we only have a single point at which parallel execution runs, but we’re likely going to have multiple points during the frame to make sure that you can complete all of the important fork/join work during one frame.

9 Likes

Yeah I think you’ll get separate data stores if you use Rodux? Which is probably not what you want :slight_smile:

This feature works best for cases where you either have a dedicated data parallel system you’d like to run, or when you model independent entities that interact with the world and would like to simulate them in parallel; it’s probably not best for things like UI code.

9 Likes

We’ll have a way to exchange data between actors in later releases; data can be exchanged between parallel and serial sections of the code by just sharing it, the raytracer example shows this well.

BindableEvent.Fire and BindableFunction.Invoke right now aren’t white listed for parallel execution; Fire should work in the future though.

6 Likes

Right now the answer is “no”… I think? :slight_smile: You definitely can’t change the fields even if you can create the instance, yet.

We do plan to fix this; we thought originally that the first beta release would have this, but unfortunately there are some complications with allowing this in a way where you can’t crash the engine with this mechanism… so in this preview you can’t change instances at all even if you just created them.

7 Likes

I think I might be confused – if I have a loop that iterates through a bunch of Instances, and gets a property from them, then does a bunch of processing based on that property, when would be the appropriate time to desynchronize it? My inclination would be to do it directly after I access the property, but that seems to just outright slow down execution, which is unexpected – I know it’s easy to do that with multi-threading but I don’t think switching desynchronizing code that creates a bunch of strings should do that.

2 Likes

This is awesome!

So I read that usage may not fully saturate all cores, with that in mind added basic shadowmap lighting to Zeux’s demo

Obviously, the raytracer takes a decent performance hit to compute lighting, but I am sitting around 50-65% usage on all cores. Not sure if this is my programming or the parallel system.

I haven’t finished reading this thread so I am not sure which questions have already been answered regarding proper ussage but I assume that we’re going to get some more documentation in the future?

EDIT: Just discovered a crash lol. Apparently putting wait(); inside :ConnectParallel makes studio angry.

26 Likes

So if I am reading this correctly, we simply but all the scripts into a new “Actor” instance and roblox will automatically put it onto a thread/core? Im somewhat confused lol

8 Likes

Mutlithreading is an exciting feature for advanced software engineers. It will certainly raise the bar for what users expect out of Roblox games: the games made by the best developers will be reaching new heights in terms of functionality and performance.

This brings up an interesting thought that’s been swirling around in my mind for a while after reading this topic.

Multithreading is notoriously tricky. Even experienced software engineers make mistakes when it comes to thread safety. With that in mind, I think about how many developers on Roblox seem to struggle to understand even basic things such as Roblox’s networking relationship between the server and clients, and how even fewer understand its implications adequately enough to understand how to engineer their servers to securely handle client requests.

Do you see multithreading becoming an error-phone challenge that new developers will have to overcome and struggle with regularly before deploying reliable games? Do you see average developers often making mistakes with multithreading that cause players’ clients to crash, thereby potentially risking the overall perception of the reliability and quality of Roblox games?

6 Likes