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.4 KB)

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

11 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

I feel like it might be more beneficial (especially with the nature of what this aims todo) to use Promise for more consistent/predictable results overall with Parallel Threading overall.

In the end, this module does seem cool for sure and not using Promises isn’t a deal breaker for me and I might go through and use it (and if not; this will be a great resource for me to look into for my own custom solution that wouldn’t see a open source release!)

i can’t seem to get an updated version of this? inserting the rbxm seems to insert the first release, evidenced by the function still being named BulkWork and having Promise packed in.
the packagelink says its version number 1 and i can’t do anything to change it. and when i insert it studio prints “Error AutoUpdating Package: Request Failed” to the output

Hmm, I don’t know not gonna lie, I’ll update the download link to see if that helps

Download link updated, please try redownloading

1 Like

just woke up again so sorry for the slow reply, but it seems to be working now :+1:

1 Like

I also have my own parallel luau library. I’ve tested a couple of benchmark methods, and just scaling a vector3 region doesn’t really showcase the full power of the parallelism, since its just multiplication and addition, just some light calculation that can be done (maybe faster) in serial

Yeah… not gonna lie I was just kinda too lazy to make something like a voxel engine for demonstration purposes xd, I am currently working on a semi-random world gen utilizing this module though, so once it’s done I’ll show it off as a nice demonstration… for now though that’s all I have right now

2 Likes

True, I’ve tried to come up with a simple yet powerful demo, but all I could do is some ASCII Shader (stupid editableimage getting locked behind a id verification wall)

Best of luck :raised_hands:

1 Like