Resync - Yet another parallel Luau library

Resync

Parallel Luau library with a simple synchronous thread pool API for dispatching tasks.

Links

About

Resync introduces a ThreadPool class that can be used to perform tasks in parallel. The ThreadPool class provides an easy-to-use synchronous API for queuing and dispatching tasks, making it simple to execute parallel tasks from a serial context.

Why use this over all the other parallel computing libraries?

Like all other resources I’ve published over the years, the point of Resync is not to compete with existing or future solutions. Make your choice based on whichever library provides an API that fits your specific use cases or preferences.

Benchmarks

Benchmark figures


Average time per sample taken to calculate a varying number of octaves of 4-dimensional fractal noise. Parallel benchmarks were done by dispatching one task per sample. Unsafe thread pools have Resync’s optional thread scheduling safety disabled.


Similar benchmark repeated with a much higher number of octaves per sample.

Installation

Two different installation methods are supported:

Rojo with Wally

  1. Install Rojo and Wally.
  2. Add Resync as a dependency in your wally.toml file.
    [dependencies]
    resync = "tenx29/resync@1.0.1"
    
  3. Run wally install.

Manually in Roblox Studio

  1. Get the latest version of Resync from the GitHub Releases page or the Roblox Creator Store.
  2. Insert the model to your project and place it to the location of your choice. ReplicatedStorage is recommended as it allows both client and server code to access it.
  3. Require the Resync ThreadPool class in your code.
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local ThreadPool = require(game.ReplicatedStorage.Resync.ThreadPool)
    

Code Example

Below is a very simple code example showcasing how to use Resync to run tasks in parallel. More in-depth instructions and a comprehensive listing of available methods can be found in the documentation.

MyTaskModule, a ModuleScript used as the worker function

return function(actor: Actor, threadId: number, message: string)
    task.desynchronize()
    task.wait(2) -- Simulate work
    print(message)

    -- Optional, Resync takes care of synchronization after the task is done
    task.synchronize()
end

Script that creates the thread pool and dispatches the tasks. For this example, the script is located in the same place as MyTaskModule.

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ThreadPool = require(ReplicatedStorage.Resync.ThreadPool)
local MyTaskModule = script.Parent.MyTaskModule -- Note that require() isn't called

-- Create a thread pool with 64 threads
local myThreadPool = ThreadPool.new(MyTaskModule, 64)

-- Add 64 tasks to the thread pool
for i = 1, 64 do
    -- The Add method can accept any number of arguments of any type,
    -- which are passed to the worker function after the thread's Actor and ID
    myThreadPool:Add(`Task {i} done!`)
end

-- Execute all tasks and wait for them to finish.
myThreadPool:DispatchAll()

-- If we wanted to combine the results of all threads, we could for example use 
-- a buffer and pass the buffer offset as an argument to the worker function.
-- Implementation details like this aren't included in Resync as it's specific to
-- the user's use cases. This is left up to the user to implement.

License

Resync is fully open-source and free to use with an MIT license.

4 Likes