src/viewer/scene/utils/WorkerPool.js
/**
* @author Deepkolos / https://github.com/deepkolos
*/
export class WorkerPool {
constructor(pool = 4) {
this.pool = pool;
this.queue = [];
this.workers = [];
this.workersResolve = [];
this.workerStatus = 0;
}
_initWorker(workerId) {
if (!this.workers[workerId]) {
const worker = this.workerCreator();
worker.addEventListener('message', this._onMessage.bind(this, workerId));
this.workers[workerId] = worker;
}
}
_getIdleWorker() {
for (let i = 0; i < this.pool; i++)
if (!(this.workerStatus & (1 << i))) return i;
return -1;
}
_onMessage(workerId, msg) {
const resolve = this.workersResolve[workerId];
resolve && resolve(msg);
if (this.queue.length) {
const {resolve, msg, transfer} = this.queue.shift();
this.workersResolve[workerId] = resolve;
this.workers[workerId].postMessage(msg, transfer);
} else {
this.workerStatus ^= 1 << workerId;
}
}
setWorkerCreator(workerCreator) {
this.workerCreator = workerCreator;
}
setWorkerLimit(pool) {
this.pool = pool;
}
postMessage(msg, transfer) {
return new Promise((resolve) => {
const workerId = this._getIdleWorker();
if (workerId !== -1) {
this._initWorker(workerId);
this.workerStatus |= 1 << workerId;
this.workersResolve[workerId] = resolve;
this.workers[workerId].postMessage(msg, transfer);
} else {
this.queue.push({resolve, msg, transfer});
}
});
}
destroy() {
this.workers.forEach((worker) => worker.terminate());
this.workersResolve.length = 0;
this.workers.length = 0;
this.queue.length = 0;
this.workerStatus = 0;
}
}