Package Exports
- @sinclair/threadbox
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@sinclair/threadbox) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Example
As above
import { spawn, Main, Worker } from '@sinclair/threadbox'
@Worker() class WorkerA {
run() {
// do work
}
}
@Worker() class WorkerC {
run() {
// do work
}
}
@Worker() class WorkerB {
async run() {
const c_0 = spawn(WorkerC)
const c_1 = spawn(WorkerC)
const c_2 = spawn(WorkerC)
const c_3 = spawn(WorkerC)
await Promise.all([
c_0.run(),
c_1.run(),
c_2.run(),
c_3.run(),
])
await c_0.dispose()
await c_1.dispose()
await c_2.dispose()
await c_3.dispose()
}
}
@Main() default class {
async main() {
const a = spawn(WorkerA)
const b = spawn(WorkerB)
await Promise.all([
a.run(),
b.run()
])
await a.dispose()
await b.dispose()
}
}
Overview
ThreadBox is a threading library for NodeJS. It is built on top of the NodeJS worker_threads
API and uses a recursive pattern to spawn new worker threads. ThreadBox will spin up the application entry module (typically app.js
) for each spawned worker. Because each spawned worker shares the same entry as the main thread, class
and function
definitions are available to each spawned worker. This pattern allows for same file threading and generally a more intuitive programming model than spreading related logic across multiple .js
files.
ThreadBox is primarily written for use with TypeScript but does provide a no decorator fallback API for JavaScript users. This library is offered as is to anyone who may find it of use.
Built with Node 12.16.1 LTS and TypeScript 3.8.3.
Licence MIT
Install
$ npm install @sinclair/threadbox --save
Contents
Main
A decorator that denotes a class as the program entry point. The classes main(...)
function will be called when the program is run. There can only be one @Main()
entry point defined within the program.
import { Main } from '@sinclair/threadbox'
@Main() class Program {
main(argv: string[]) {
console.log('hello world')
}
}
// JavaScript users can use __Main(Program) if
// decorators are not available.
Worker
Denotes a class as worker thread which allows it to spawn()
. Any class may be denoted as a @Worker()
. When spawned, the parent thread will be able to execute all of the the classes functions (see spawn()
section for details). The classes constructor
will be called when the worker is created and the dispose()
method will be called when the parent thread has choosen to dispose()
the worker.
import { Worker } from '@sinclair/threadbox'
@Worker() class Processor {
constructor() {
console.log('worker started')
}
add(a: number, b: number) {
return a + b
}
subtract(a: number, b: number) {
return a - b
}
dispose() {
console.log('worker disposed')
}
}
// JavaScript users can use __Worker(Processor) if
// decorators are not available.
Transfer
Denotes a class as being transferrable. It enables instances of this class to be marshalled across thread boundaries.
import { Transfer } from '@sinclair/threadbox'
@Transfer() class Foo {
method() {
console.log('hello world')
}
}
// JavaScript users can use __Transfer(Foo) if
// decorators are not available.
Internally, ThreadBox communicates between threads using postMessage(...)
. However, only data can be sent, not functions. Passing class instances to threads will result in a loss of that classes functions at the receiver. The @Transfer
decorator informs ThreadBox that it should marshall and reconstruct instances of the class at the receiver.
This functionality allows logic to be passed from parent thread to worker thread without manually needing to reconstruct the appropriate class instance at the receiver.
spawn()
Will spawn any class marked as @Worker
. This function returns a proxy to the class which can be used to invoke the classes methods.
import { spawn, Main, Worker, WorkerInterface } from '@sinclair/threadbox'
@Worker() class Bar {
method() {
console.log('inside bar thread')
}
}
@Worker() class Foo {
private bar: WorkerInterface<Bar>
constructor() {
this.bar = spawn(Bar)
}
async method() {
console.log('inside foo thread')
await this.bar.method()
}
async dispose() {
await this.bar.dispose()
}
}
@Main() class Program {
async main() {
const foo = spawn(Foo)
await foo.method()
await foo.dispose()
}
}
// > inside foo thread
// > inside bar thread
The return type of spawn()
is a WorkerInterface<T>
. It provides all the classes methods and one additional method named dispose()
that will terminate the worker.
All functions on WorkerInterface<T>
are async.