Worker threads module

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

19 Likes