Recently parallel lua was released so I decided to make a worker “threads” module (technically not threads but, workers which are just actors) since there was no way to run several functions in parallel by calling some function from the task library except by interacting with actors and cloning them, etc. This can get pretty messy and, it can be a pain to setup a function to run on both the server and the client since it would require you to copy the contents of a script and move them to either a local script or a server sided script (just a script).
The module comes with an example which renders fractals by distributing work across workers/actors.
Note: The reason functions can’t be sent to the module is because you can’t send functions to different actors since they’re a part of different VMs, this doesn’t make sense for pure functions but, ( ͡° ͜ʖ ͡°) ( ͡° ͜ʖ ͡°) ( ͡° ͜ʖ ͡°)
API:
Module.New(Module [Instance], Job [String (key of a function in Module)], NumWorkers [Number/Integer]) [Returns a workers object]
Workers:DoWork(… [Parameters]) [Returns result from calling function in parallel]
Workers:NewWorker() [Creates a new worker, I recommend passing the number of workers you need to Module.New instead]
Workers:Clean() [Will remove all actor instances, make sure to remove references to the object this is called on]
Example:
-- module
local Module = {}
function Module.Sum(Start, End)
local n = 0
for i = Start, End do
n += i
end
return n
end
return Module
-- script
local WorkerThreads = require([LOCATION OF WORKER THREAD MODULE])
local Module = [LOCATION OF MODULE FROM ABOVE]
local NumWorkers = 64
local Workers = WorkerThreads.New(Module, "Sum", NumWorkers)
local function Sum(Start, End) -- this assumes that End - Start is a factor of NumWorkers (so this example script doesn't get unnecessarily long)
local Difference = End - Start
local NumbersPerWorker = Difference/NumWorkers
local JobsComplete = 0
local NextEnd = Start + NumbersPerWorker
local RunningTotal = 0
local Thread = coroutine.running()
for i = 1, NumWorkers do
task.spawn(function()
local ret = Workers:DoWork(Start, NextEnd)
RunningTotal += ret
JobsComplete += 1
if JobsComplete == NumWorkers then
coroutine.resume(Thread)
end
end)
Start = NextEnd + 1
NextEnd = NextEnd + NumbersPerWorker
end
coroutine.yield()
return RunningTotal
end
print(Sum(NumWorkers, NumWorkers * 10000000)) -- There are better ways to find the sum of all natural numbers between 2 numbers but, this is an example showing how actors/workers may be used
MicroProfiler output
The output above shows 4 cores being utilised to calculate the sum in the script above.
An actual example:
The example game has 4 possible fractals which are randomly picked using math.random