While this method of parallel execution is useful for some tasks, it’s useless for one of the biggest use cases of multi-threading, offloading singular heavy tasks to separate cores so they don’t bog down the main thread. Since the main thread always waits for all parallel threads to complete before continuing, offloading expensive tasks to another thread is useless. It’s also impossible to run tasks that take several frames to complete for the same reason.
I think a system that allows running a pure function on another thread and simply runs a callback when it completes would be fairly simple to add. I hope an API for this kind of use case is released in the future.
I also think a more efficient method of data replication between the threads is needed. Currently the only way to send pure data between threads/actors is to send it through a BindableEvent/BindableFunction, which has a high serialization cost. For my use case, the cost of sending the data was an order of magnitude higher than the cost of the operation itself.
I’m currently having an issue using the MicroProfiler with scripts utilizing parallel lua.
If you put a script inside an actor
And then you set up a simple script that runs in parallel
game:GetService("RunService").RenderStepped:ConnectParallel(function()
debug.profilebegin("Test Profile") -- setting up the microprofiler
task.synchronize() -- running code in serial
for i = 1, 5000000 do end -- lag machine for microprofiler
task.desynchronize() -- the issue runs with or without putting the script back in parallel
debug.profileend() -- warns in console
end)
As a result, you’ll see a warning in the output window that looks like this
This happens because when you run task.synchronize it changes the stack trace of the script since it’s moving it into the serial. As a fix to get around the flood of warnings in my output, I am forced to call debug.profileend anytime I want to switch between running in serial or parallel
The work around looks something like this:
game:GetService("RunService").RenderStepped:ConnectParallel(function()
debug.profilebegin("Test Profile")
debug.profileend()
task.synchronize()
debug.profilebegin("Test Profile")
for i = 1, 5000000 do end
debug.profileend()
task.desynchronize()
debug.profilebegin("Test Profile")
debug.profileend()
end)
Obviously it’s unrealistic how I’m handling the microprofiler labels in this sample code, but when you start having to work with something like a large renderstep update function that requires switching between running in serial and in parallel, and you need to create these microprofiler labels, the code starts getting messy real quick.
TL;DR
Will there be a simpler support for using the debug.profile functions when having to switch between running in serial or parallel?
Do roblox servers have Actors active? I have a script that works perfectly on the studio local server, but seems to run in Serial instead of Parallel on actual roblox servers.
After a bit of debugging, it seems like roblox server don’t have parallel lua active, only the client?
Is there any plan to allow us to access some sort of shared read-only data among actors? I have a custom raycast solution, and I would like to make parallel raycast calls, but there is no way that I’m aware of to read data from my BVH from separate actors without outright initializing said actors by sending massive tables over via bindableevents. I’m aware of the problems that come from having multiple threads reading and writing to the same memory, which is why I suggested the memory be read-only (can only be written to by one thread at a time, or maybe serial only?)
I have a bunch of questions regarding parallel Luau.
Do scripts have to be inside an actor to spawn multiple threads?
Could I for example… create 4 threads inside a single script? How?
And how does parallel Luau handle logic that makes use of module scripts and metatables?
In a module script (in ReplicatedStorage):
local class = {}
function class:new()
self.__index == self
local o = {}
setmetatable(o, self)
return o
end
function class:doParallelThing()
-- Parallel code
end
In a script that’s located inside an actor:
local object = require(PathToClass):new()
object:doParallelThing()
I use an object oriented design and I’m still figuring out how I can use parallel Luau with it.
Documentation and information on module scripts and how it all works is still limited and sometimes a bit vague.
I would greatly appreciate some clarification and explanation.
I noticed that if you create actors and destroy them after use, their memory stay and starts increasing if more are created and destroyed on the console, is this how it should actually work? shouldn’t the memory be cleaned if the actor was destroyed? or should we stick with a set number of actors instead of creating and destroying them when you use/finish using?
My current approach is to just have a folder with actors and parent scripts under it, if I no longer need them destroy the scripts instead of the actors.