Spaces:
Sleeping
Sleeping
| /** | |
| * WorkerPool.js | |
| * Hardware-scaling worker thread pool manager with zero-copy transfers and synchronous fallbacks. | |
| */ | |
| import { | |
| executeResampleZFallback, | |
| executeDeltaAndSimilarityFallback, | |
| executeVarianceSortFallback | |
| } from '../visualizer/ReliefMath.js'; | |
| export class WorkerPoolManager { | |
| constructor(size = null) { | |
| this.poolSize = size || Math.max(1, Math.min((typeof navigator !== 'undefined' && navigator.hardwareConcurrency) || 4, 8)); | |
| this.workers = []; | |
| this.idleWorkers = []; | |
| this.taskQueue = []; | |
| this.activeTransactions = new Map(); | |
| this.transactionId = 0; | |
| this.isSupported = typeof window !== 'undefined' && typeof window.Worker !== 'undefined'; | |
| if (this.isSupported) { | |
| this.initializePool(); | |
| } | |
| } | |
| initializePool() { | |
| for (let i = 0; i < this.poolSize; i++) { | |
| try { | |
| const worker = new Worker( | |
| new URL('../workers/mathWorker.js', import.meta.url), | |
| { type: 'module' } | |
| ); | |
| worker.onmessage = (e) => this.handleMessage(i, e.data); | |
| worker.onerror = (err) => this.handleError(i, err); | |
| this.workers.push(worker); | |
| this.idleWorkers.push(i); | |
| } catch (e) { | |
| this.isSupported = false; | |
| break; | |
| } | |
| } | |
| } | |
| postTask(taskName, payload, transferables = []) { | |
| if (!this.isSupported) { | |
| return this.runFallback(taskName, payload); | |
| } | |
| return new Promise((resolve, reject) => { | |
| const currentTxId = this.transactionId++; | |
| const task = { | |
| transactionId: currentTxId, | |
| taskName, | |
| payload, | |
| transferables, | |
| resolve, | |
| reject | |
| }; | |
| this.activeTransactions.set(currentTxId, task); | |
| this.taskQueue.push(task); | |
| this.processQueue(); | |
| }); | |
| } | |
| processQueue() { | |
| if (this.taskQueue.length === 0 || this.idleWorkers.length === 0) return; | |
| const workerIdx = this.idleWorkers.pop(); | |
| const task = this.taskQueue.shift(); | |
| const worker = this.workers[workerIdx]; | |
| try { | |
| worker.postMessage({ | |
| task: task.taskName, | |
| payload: task.payload, | |
| transactionId: task.transactionId | |
| }, task.transferables); | |
| } catch (err) { | |
| this.handleError(workerIdx, err); | |
| } | |
| } | |
| handleMessage(workerIdx, messageData) { | |
| const { transactionId, status, data, similarity, sortedIndices, variances, error } = messageData; | |
| const task = this.activeTransactions.get(transactionId); | |
| if (!task) return; | |
| this.activeTransactions.delete(transactionId); | |
| this.idleWorkers.push(workerIdx); | |
| if (status === 'success') { | |
| task.resolve({ data, similarity, sortedIndices, variances }); | |
| } else { | |
| task.reject(new Error(error)); | |
| } | |
| this.processQueue(); | |
| } | |
| handleError(workerIdx, error) { | |
| console.warn('[WorkerPool] Error en worker. Cambiando a ejecución síncrona.', error); | |
| this.isSupported = false; | |
| if (this.workers[workerIdx]) { | |
| try { this.workers[workerIdx].terminate(); } catch (_) {} | |
| } | |
| for (const [txId, task] of this.activeTransactions.entries()) { | |
| this.runFallback(task.taskName, task.payload) | |
| .then(task.resolve) | |
| .catch(task.reject); | |
| this.activeTransactions.delete(txId); | |
| } | |
| } | |
| runFallback(taskName, payload) { | |
| return new Promise((resolve, reject) => { | |
| try { | |
| switch (taskName) { | |
| case 'resampleMatrixZ': { | |
| const { sourceData, sourceZ, sourceX, targetZ, targetX } = payload; | |
| const res = executeResampleZFallback(sourceData, sourceZ, sourceX, targetZ, targetX); | |
| resolve({ data: res }); | |
| break; | |
| } | |
| case 'computeDeltaAndSimilarity': { | |
| const { matrixA, matrixB, length } = payload; | |
| const res = executeDeltaAndSimilarityFallback(matrixA, matrixB, length); | |
| resolve({ data: res.delta, similarity: res.similarity }); | |
| break; | |
| } | |
| case 'sortDimensionsByVariance': { | |
| const { data, rows, cols } = payload; | |
| const res = executeVarianceSortFallback(data, rows, cols); | |
| resolve({ sortedIndices: res.indices, variances: res.variances }); | |
| break; | |
| } | |
| default: | |
| reject(new Error(`Fallback unsupported for task: ${taskName}`)); | |
| } | |
| } catch (err) { | |
| reject(err); | |
| } | |
| }); | |
| } | |
| terminateAll() { | |
| this.workers.forEach(w => { | |
| try { w.terminate(); } catch (_) {} | |
| }); | |
| this.workers = []; | |
| this.idleWorkers = []; | |
| this.activeTransactions.clear(); | |
| } | |
| } | |
| export const WorkerPool = new WorkerPoolManager(); | |