Concurrencia y multihilo en JavaScript: nivel avanzado

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Concurrencia y multihilo en JavaScript: nivel avanzado



JavaScript ha sido históricamente un lenguaje de un solo hilo que funciona dentro del bucle de eventos (Event Loop). Sin embargo, las aplicaciones modernas en Node.js requieren un alto rendimiento al procesar tareas intensivas en CPU. En este artículo, analizaremos los mecanismos avanzados de concurrencia y multihilo: Worker Threads, SharedArrayBuffer, Atomics y clustering. Aprenderá cómo utilizar eficazmente los procesadores multinúcleo y evitar el bloqueo del hilo principal.



1. Worker Threads: verdadero multihilo en Node.js



El módulo worker_threads apareció en Node.js 10.5.0 y permite crear hilos separados con su propio motor V8. A diferencia del clustering (procesos), Worker Threads comparten memoria y pueden intercambiar datos a través de SharedArrayBuffer.



Creación y ejecución de un worker



// main.jsconst { Worker } = require('worker_threads');

function runWorker(data) { return new Promise((resolve, reject) => { const worker = new Worker('./worker.js', { workerData: data }); worker.on('message', resolve); worker.on('error', reject); worker.on('exit', (code) => { if (code !== 0) reject(new Error(`Worker stopped with exit code ${code}`)); }); });}

(async () => { const result = await runWorker({ numbers: [1, 2, 3, 4, 5] }); console.log('Resultado:', result); // { sum: 15 }})();


// worker.jsconst { parentPort, workerData } = require('worker_threads');

const sum = workerData.numbers.reduce((acc, val) => acc + val, 0);parentPort.postMessage({ sum });


Importante: Los workers no tienen acceso al DOM ni a módulos que requieran el hilo principal. Úselos para cálculos pesados, procesamiento de imágenes o cifrado.



2. SharedArrayBuffer y Atomics: memoria compartida



SharedArrayBuffer permite que varios workers lean y escriban datos en una misma área de memoria. Para sincronizar el acceso se utiliza el objeto Atomics, que garantiza operaciones atómicas.



Ejemplo: procesamiento paralelo de un array



// main.jsconst { Worker } = require('worker_threads');const { SharedArrayBuffer } = require('worker_threads');

const buffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 10);const array = new Int32Array(buffer);

// Llenamos el arrayfor (let i = 0; i < 10; i++) array[i] = i;

const worker1 = new Worker('./worker_atomics.js', { workerData: { start: 0, end: 5 } });const worker2 = new Worker('./worker_atomics.js', { workerData: { start: 5, end: 10 } });

worker1.on('message', () => console.log('Worker 1 terminó'));worker2.on('message', () => console.log('Worker 2 terminó'));


// worker_atomics.jsconst { parentPort, workerData } = require('worker_threads');const { Atomics } = require('worker_threads');

const buffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 10);const array = new Int32Array(buffer);

// Incremento atómico de cada elementofor (let i = workerData.start; i < workerData.end; i++) { Atomics.add(array, i, 10);}

parentPort.postMessage('done');


Nota: Use Atomics.wait() y Atomics.notify() para la sincronización de hilos (análogo a los mutex). Esto es fundamental para prevenir condiciones de carrera.



3. Clustering: escalado mediante procesos



El módulo cluster crea varios procesos de Node.js (workers), cada uno de los cuales maneja solicitudes. Esta es la forma estándar de escalar servidores HTTP en sistemas multinúcleo.



Ejemplo: servidor HTTP clusterizado



const cluster = require('cluster');const http = require('http');const numCPUs = require('os').cpus().length;

if (cluster.isMaster) { console.

Blogs

Book Recommendations