ActorGroup | Split Heavy Computation Into Parallel Threads

ActorGroup is a utility module I’ve made for the purposes of doing heavy computations (such as frequent spatial queries or generating big arrays) fast by splitting it up into multiple Actors.

This module uses queues to manage workers as to not overload a single Actor with tasks when there are free Actors.

Documentation:

Constructor

The constructor for ActorGroup is quite straightforward, but it can still be pretty confusing, so here I will explain it.

The first argument module is a ModuleScript that returns a function for Actors to call with provided arguments when they recieve a message to work.
This works similarly to ParallelScheduler

The second argument count is simply how many Actors you want to create that are able to run the function returned by module in different threads.
For my purposes (spatial queries) I set count to 10, but you can increase it if the need arises.

Methods
  1. ActorGroup:Call(...: any): any

    • This function finds the first free worker, and sends a “Work” message to it, alongside the arguments ...
      The returned value is the value that the Actor has recieved by calling the module function.

  2. ActorGroup:Destroy()

    • Yields until all work is done, then destroys all of the Actors.
Example Usage

In a module called “HeavyMaths”

return function(cframe, size)
	local query = workspace:GetPartBoundsInBox(cframe, size)
	
	return query
end

In its parent Script:

local RunService = game:GetService('RunService')

local ActorGroup = require(game.ReplicatedStorage.ActorGroup)

local heavyMaths = script.HeavyMaths

local group = ActorGroup.new(heavyMaths, 20)

RunService.Heartbeat:Connect(function()
	local query = group:Call(workspace.Part.CFrame, workspace.Part.Size)
	
	print(query)
end)

You can test this code out for yourself, but there is little to no lag from this, it is very nice!

Side Notes

All workers recieve messages via Actor:BindToMessageParallel(), so if you plan to do non-parallel safe activities in the module function make sure to call task.synchronize() first.

Download →
ActorGroup.rbxm (6.1 KB)

5 Likes

From my understanding this is a wrapper but it utilises actors for speed?

very very interesting module

thrity*

No it just makes multiple actors and by calling :Call() you use a free one to call a provided function (returned by module when doing .new() ) in parallel and then it returns the result to you.

1 Like

Interesting. I will look at this later at some point likely. Cool addition.

Looks interesting! Will this also help with cloning large models (10k parts)?

Since cloning is a singular task, I suppose it won’t make much of a difference, but I am still getting started with parallel Luau, so I could be wrong.

Unfortunately cloning instances is a non-parallel safe interaction so no

1 Like