ActorGroup2 | Asynchronous parallel luau made easy

ActorGroup2 is a rework of my original module ActorGroup, but heavily optimized to use buffers (as in a table to collect results, not a buffer), a single BindableEvent for results, callbacks, etc to ensure you can do heavy calculations fast.

Documentation:

Constructor

There is currently only 1 constructor for ActorGroups.

  1. ActorGroup2.new(module: ModuleScript, count: number)

    • This constructor creates a new ActorGroup with a module (similar to the ParallelScheduler module), and an amount of workers made count (so for example if count was 128, 128 workers (Actors) would be made.)
Methods
  1. ActorGroup:BulkWorkAsync(callback: (results: {any}) -> (), assignments: {any})

    • This method assigns each value in the assignments table to a worker, and calls callback with the results once it is done.
      Note that the number of assignments cannot be more than the number of workers, because as said before, each value is assigned to exactly 1 worker.

  2. ActorGroup:WorkAsync(callback: (result: {any}) -> (), assignment: any)

    • BulkWorkAsync() but for a single worker.

  3. ActorGroup:AwaitBulkWorkAsync(assignments: {any}): {any}?

    • Yields until the work is finished, then returns the result (unlike `BulkWorkAsync() which requires a callback)

  4. ActorGroup:AwaitWorkAsync(assignment: any): {any}?

    • Self explanatory.
  5. ActorGroup:BatchAssignments(assignments: {any}, batchSize: number?): {{any}}

    • This is a utility method to split an array of assignments into batches based on the number of workers.
      Useful if your existing code doesn’t implement batches, but you still want to use them.

  6. ActorGroup:Destroy()

    • Removes the ActorGroup from memory.

ActorGroup Best Practices

For the purposes of doing heavy calculations, it is recommended to make your module able to handle multiple calculations at once.

For example, this is reading a 500x500 stud region of Terrain with this best practice in mind, completed in 0.4s:



And this is the same computation, but this time each worker is assigned a single Region3 to compute:


Not only is it slower, it also requires more workers (because each value in the assignments table passed in :BulkWork() is assigned to exactly 1 worker.)

Reading a 1000x1000 stud region of Terrain completed in 0.5s!

Download ActorGroup2 here →
ActorGroup.rbxm (6.1 KB)

If you have any features to suggest, feel free to post it down in the replies section.

7 Likes

Update: Added the :BatchAssignments() method to conveniently batch an assignment array into multiple nested arrays containing those assignments. Very useful if you want to do stuff in bulk but don’t want to modify existing logic

1 Like

Update:

  • Removed the use of Promises in favor of simple callbacks
1 Like

Any reasons why you’ve decided to drop using Promise?

Out of curiosity as this is in my radar for potential use.

Dunno, just figured it’d be simpler and also more similar to how alot of Roblox async functions work

1 Like

Update:

  • Renamed ActorGroup:BulkWork() to ActorGroup:BulkWorkAsync()

  • Renamed ActorGroup:RandomWork() to ActorGroup:WorkAsync()

  • Added ActorGroup:AwaitWorkAsync() and ActorGroup:AwaitBulkWorkAsync() for those who prefer to wait instead of using callbacks

  • Added a ActorGroup:Destroy() method

  • Added docstrings for all the functions

  • Added a queue for free workers (let me know if this impacts performance!)

1 Like

Oh yeah, the queues definitely affected performance, made 0.4s turn into 0.7s!

I’m removing them.

1 Like

Cool module!?!?!?!? Lol

1 Like