@little-island/workers v0.1.8
Workers
These are some classes that will help easily use and manage WebWorkers in the projects you are working on. It's loosely based on SimonDev's Threading Technique with JavaScript WebWorkers that he used for his procedural world generation.
How it works
The most likely reason you would need to use many workers in projects is to complete complicated and performance-crippling tasks on different threads. I have created two classes that make doing this a walk in the park; WorkerThreadPool
and WorkerThread
.
WorkerThreadPool (options?: object)
This class essentially manages all the workers you create within it. It allows to run as many workers as you want at once as long as it is less than or equal to the amount if threads on your CPU. If you run more workers than the maxUsableThreads
you have allowed it to use, it will queue those workers to run as soon as there is an empty thread available for it (like when one of the previous workers finishes its task). This allows for very easy management without haing to hastle to much with the performance.
- constructor
(options? object)
Sets the max amount of threads that this pool is allowed to use (default is your CPU thread count).- add
(workerThread? WorkerThread): void
Stores a worker in this pool under its UUID.- enqueue
(workerThread? WorkerThread): void
This adds the worker to the queue if all the threads are busy and if it hasn't already been placed inside the queue.- createWorker
(fileName: string, options?: object): WorkerThread
This creates and returns a new worker and stores it in this pool.- isBusy
(workerThread: WorkerThread): boolean
Checks if the worker is busy.- isQueued
(workerThread: WorkerThread): boolean
Checks if the worker is in the queue.- checkMessage
(workerThread: WorkerThread): void
This is called when a worker has completed its task. It removes the worker from the "busy" list and runs the next worker in the queue. If it isn't a permanent worker, it remove it this pool's storage and terminate it.- run
(workerThread: WorkerThread): void
This decides if the worker should be executed and become "busy", or be put in the queue to be executed when a thread is available.- test
(): void
This creates a bunch of sample workers to test if this pool is queueing, executing, and terminating workers properly.
WorkerThread
This class contains the actual WebWorker. You can use tell it what data to send and what to when its task is complete. Unless the permanent
option is set to "true", the worker will automatically terminate itself when its task is complete.
- constructor
(pool: WorkerThreadPool, fileName: string, options? object)
Sets the thread pool that this worker will be assigned to and builds the WebWorker plus its default actions. Finally it stores this worker in the thread pool for later use.- postDirectMessage
(data?: object): void
Directly posts a message to the WebWorker without the help of the thread pool. This might interfere with the performance since it could possible execute when the threads are overloaded.- postMessage
(data?: object, resolve?: void): void
Tells this worker what data to send and what to do when the its task is completed. Once called, it will send this worker to the thread pool to either be queued or executed based on how many threads are currently busy.- terminate
(): void
Gets rid of this worker from memory.
Usage
There are a couple ways to use this, but below is the way it was intended
import { WorkerThreadPool } from '@little-island/ecs'
// let's create the thread pool we are tell it to only queue a max of 2 workers at once.
// This usually defaults to the number of threads your CPU has available.
const ThreadPool = new WorkerThreadPool( { maxUsableThreads: 2 } )
//-------------------------
/** Define some workers */
//-----------------------
// this worker takes two numbers and multiplies them together and squares them (it's a module by default).
const Worker1 = ThreadPool.createWorker( './workers/mathThing.js' )
//this worker takes an array and reverses the order of its contents and adds "animal:" to the beginning of each one.
const Worker2 = ThreadPool.createWorker( './workers/animals.js', { type: 'classic' } )
//this worker just posts "Hello wide world!".
const Worker3 = ThreadPool.createWorker( './workers/hello-world.js', { type: 'module' } )
//this worker just posts "I will stay here..." and is permanent.
const Worker4 = ThreadPool.createWorker( './workers/mr-steady.js', { permanent: true, type: 'module' } )
//-----------------------------------------------
/** Execute and send workers to do some tasks */
//---------------------------------------------
// e.result is 784
Worker1.postMessage( { num1: 7, num2: 4 }, ( e ) => { console.log( e.result ) } )
// e.newArray is [ "animal:fish", "animal:cat", "animal:dog" ]
Worker2.postMessage( [ 'dog', 'cat', 'fish' ], ( e ) => { console.log( e.newArray ) } )
// this worker will be queued since all 2 threads allowed have are being occupied by the previous workers.
// Once one of the first 2 finishes its task, this worker will be removed from the queue and will be executed.
// e.message is "Hello wide world!"
Worker3.postMessage( {}, ( e ) => { console.log( e.message ) } )
// this worker runs the same way as Worker3.
// Unlike all the other workers we made though, this one will stay busy until we decide to manually terminate it.
// e.message is "I will stay here..."
Worker4.postMessage( {}, ( e ) => { console.log( e.message ) } )