For the sake of convenience I’ll call the scripts ImageRender and ImageHandler. In the screenshot you sent it looks like ImageRenders are still running serially. I suspect your render scripts might contain a yielding function like task.wait().
I’ve played with multithreading a bit. In all the cases below, the receiving script (under the same actor) of the message in “Serial” topic executes in serial the exact same loop as the one after task.synchronize().
Code
script:GetActor():BindToMessageParallel("Parallel", function()
for i=1, 1000000 do local n = i*i end
--script.Parent:SendMessage("Serial")
task.synchronize()
for i=1, 500000 do local n = i*i end
end)
Works exactly as anticipated. In the second run I executed the part after desync in another script of the same actor, which worked similarly, but what bothered me was how the phase was executed before physics simulation in the next frame, prolonging RenderJob.
Profiler
Desync in the same script:
Resumption in serial from messaging signal:
*Couldn’t capture all workers in a single image.
In the release of Parallel Luau V2 it was announced that “task.defer(), task.delay(), and task.wait() now resume in the same context (serial or parallel) that they were called in”.
One of the replies shows how an infinite loop with a task.wait() scheduled in parallel is resumed by the main worker, to which a Roblox dev responded that Parallel Luau is intended to run per-frame tasks in parallel with each other and not to run tasks that last over multiple frames, running in parallel with the engine.
Now I think we should distinguish between two cases of yielding with task.wait():
Code 1
script:GetActor():BindToMessageParallel("Parallel", function()
for i=1, 1000000 do local n = i*i end
task.wait()
script.Parent:SendMessage("Serial")
--task.synchronize()
--for i=1, 500000 do local n = i*i end
end)
Profiler 1
*Couldn’t capture all workers in a single image.
Code 2
script:GetActor():BindToMessageParallel("Parallel", function()
for i=1, 1000000 do
local n = i*i
if i==500000 then task.wait() end
end
script.Parent:SendMessage("Serial")
--task.synchronize()
--for i=1, 500000 do local n = i*i end
end)
Profiler
*Couldn’t capture all workers in a single image.
In the first case the threads evidently run in parallel on different workers as opposed to the second case, where the threads are resumed one after another - causing a lot more noticable lag. Not entirely sure why that is so, but it seems the second case mirrors your situation.
@MrChickenRocket apologies for the notification, I pinged you because you probably have more info than me.