// app.ts// start here ...default
class decorated with
Thread to be spawned and instanced in a remote worker thread. ThreadBox constructs an async interface to the remote worker
class, allowing the host thread to invoke operations on the remote worker through simple async method calls.
ThreadBox uses a recursive pattern to spawn worker threads. ThreadBox will recursively call into the applications entry module (typically
app.js) and instance a requested
Thread class when spawning a new worker. Because each new worker is spawned from the same entry module as the application,
const definitions defined by the application are also available to each subsequent thread. This approach allows for ergonomic same file threading common to other languages.
Built with Node 12.16.1 LTS and TypeScript 3.8.3.
$ npm install @sinclair/threadbox --save
ThreadBox primarily uses decorators to denote
Marshal class types. It also implements
[Symbol.asyncIterator] for channels. TypeScript users should configure their environment for the following.
// tsconfig.json"compilerOptions":"experimentalDecorators": true"downlevelIteration": true...
Main decorator registers a class as the programs entry point. The classes
main(...) function will be automatically called by ThreadBox when the program is run.
Thread decorator registers a class as threadable which allows it to be spawned in a worker thread. When spawned, the host thread will be able to execute any function available on the class. The class may additionally implement an optional
dispose() function that will be invoked when the host thread terminates the worker.
spawn(...) function will spawn a threadable class and return a handle to caller allowing it to call methods on the remote class instance. The
spawn(...) function may also accept the classes constructor arguments.
The return type of the
spawn() function is a
ThreadInterface object. This
ThreadInterface is a promisfied version of the class interface. The
ThreadInterface also provides an additional
dispose() function that is available irrespective of if the class has provided an implementation. Calling
dispose() on the
ThreadInterface will result in the worker being terminated.
ThreadBox provides a channel API that is built upon the MessageChannel API. ThreadBox channels implement a synchronization protocol that enables a
Sender to optionally
await for messages to be received by a
Receiver. ThreadBox channels are loosely modelled on Rust mpsc channels.
Receiver types can be used to stream sequences of values between cooperating threads. The
Sender will async buffer values if the caller does not
Receiver type implements
[Symbol.asyncIterator] so can be used with
The following creates a channel inside the
Main thread and sends the
Sender to the worker thread. The worker thread will emit values to the
Sender which are iterated on within the
The following creates a channel inside the worker thread and returns a
Receiver on its
stream() function. The
Main thread then spawns the worker thread and calls
stream() and awaits for the
Receiver. It then iterates on the
into() function is a util function that allows one to move into an async context.
Marshal decorator registers a class as marshalled. This enables instances of the class to be sent and reconstructed across thread boundaries. ThreadBox will automatically marshal all classes marked with
Thread function calls, as well as across a channel
This functionality allows class instances to be transferred to remote threads for remote invocation.
Note: There is a serialization cost to marshaling. For performance, only
Marshal when you need to move logic in and out of threads.
ThreadBox provides a
// critical sectionlock.dispose
The example below spawns 4 instances of the
Worker class. A
Mutex instance is passed into each worker where by the worker takes a
MutexLock on the
execute() method. The worker thread holds onto their respective lock for 1 second before releasing. Only 1 of the 4 workers will execute the critical section (below) at one time. The timeout is used to demonstrate the locking behavior.
The following demonstrates using
SharedArrayBuffer to parallelize operations performed across a shared
Float32Array. The shared buffer is sent to 4 workers with an index to store the result.