JavaScript ha sido inherentemente diseñado como una bestia de un solo subproceso. Sin embargo, en los terrenos salvajes de la informática, los depredadores conocidos como 'procesadores multinúcleo' y 'multiprocesamiento' esperan ser domesticados, listos para impulsar la ejecución de su código a velocidades inauditas. 💪🚀
Me atreví a adentrarme en esta jungla, sometí mi código a la prueba de supervivencia definitiva y emergí con resultados sorprendentes. 🏆 Ahora, es tu turno de unirte a mí en esta apasionante búsqueda. Profundizaremos en el enigma del multiprocesamiento en Node.js , armados con fascinantes ejemplos de código y alumbrando con la antorcha 🔦 los espectaculares frutos de mis experimentos. 🍎🍏
¡Prepárese para zarpar en esta aventura llena de adrenalina de sobrealimentar el rendimiento de JavaScript a través de la magia del multiprocesamiento! Abróchese el cinturón y prepárese, ya que estamos a punto de lanzarnos al fascinante reino de la codificación de alto octanaje.
Antes de aventurarnos demasiado profundo, equipémonos con algunas herramientas confiables. Diseñaremos algunas funciones auxiliares para simular el trabajo computacional a menudo arduo. Vamos a crear un nuevo artefacto, un archivo llamado utils.js
, e inscribiremos estos encantamientos esenciales allí.
// utils.js function generateRandomData(size) { const data = []; for (let i = 0; i < size; i++) { data.push(Math.random()); } return data; } function processData(data) { // performs some calculations on the array // to simulate high resource intensity let sum = 0; for (let num of data) { for (let j = 0; j < 1000000; j++) { sum += Math.sqrt(num); } } return sum; } module.exports = { generateRandomData, processData, };
La ejecución en un solo subproceso representa un enfoque trabajador y confiable para la resolución de problemas. La versión de subproceso único del script se puede describir visualmente como tal. El código de la versión de un solo subproceso es bastante sencillo. Creamos datos y los enviamos para su procesamiento.
// sync.js const { generateRandomData, processData } = require("./utils"); const data = generateRandomData(30000); console.time("single-thread. Time:"); processData(data); console.timeEnd("single-thread. Time:");
Lanzamos el script con el comando: node sync.js
Esperamos... y esperamos... y esperamos...
Y después de tanta espera, recibimos un mensaje indicando el tiempo de ejecución del script.
single-thread. Time:: 25.888s
Este enfoque se ajusta a la ley para la mayoría de los casos. Pero hay un contratiempo. ¿Quién, en su sano juicio, adora el arte de esperar? ¡Para superar este angustioso retraso, debemos aprovechar toda la potencia de fuego de nuestras computadoras! ¡Después de todo, la mayoría de las computadoras modernas vienen cargadas con más de un solo núcleo de CPU!
Entonces, ¿por qué deberíamos dejar que esos núcleos adicionales permanezcan inactivos cuando podrían estar procesando números y sobrecargando la ejecución de nuestro código ? ¡Es hora de iluminar a esos gigantes durmientes y desbloquear el poder puro del multiprocesamiento! ¡Vamos a sumergirnos!
Al adoptar el enfoque multiprocesado, podemos aprovechar múltiples núcleos de nuestra CPU, impulsando el rendimiento de nuestro script varias veces. El proceso de operación de nuestro código multiprocesado se puede visualizar con este diagrama.
En esencia, simplemente estamos dividiendo un conjunto de datos considerable en segmentos y asignando cada segmento para su procesamiento a un núcleo de CPU discreto.
Cree un archivo titulado multi-process.js
y rellénelo con el siguiente contenido.
// multi-process.js const childProcess = require("child_process"); const utils = require("./utils"); const data = utils.generateRandomData(30000); const chunkSize = Math.ceil(data.length / 4); const chunks = []; for (let i = 0; i < 4; i++) { const start = i * chunkSize; const end = start + chunkSize; chunks.push(data.slice(start, end)); } console.time("multiProcessed"); const workers = []; let results = []; // result collection array for (let i = 0; i < chunks.length; i++) { const worker = childProcess.fork("./worker.js"); // pass its number and data to the workflow worker.send({ workerNumber: i, data: chunks[i] }); workers.push( new Promise((resolve, reject) => { worker.on("message", (result) => { results.push(result); // add the result to the result array resolve(); }); worker.on("error", reject); worker.on("exit", (code) => { if (code !== 0) { reject(new Error(`Worker stopped with exit code ${code}`)); } }); }) ); } Promise.all(workers) .then(() => { console.timeEnd("multiProcessed"); console.log("Processing results:", results); }) .catch((err) => console.error(err));
Este código revela la orquestación de un proceso de trabajador solitario en la sinfonía del manejo de datos multiprocesados en Node.js.
En resumen, esto es lo que está sucediendo:
El trabajador recibe datos y su número del proceso principal a través de process.on('message')
.
La función processData
realiza cálculos sobre la porción de datos asignados a este trabajador.
El resultado se envía de vuelta al proceso principal a través de `process.send()``.
El trabajador termina con el código 0 a través de process.exit()
.
Inicie el script con el comando: node multi-process.js
Agárrate fuerte para el impulso turbo...
¡Y llegamos a la conclusión de que el código funcionó en 5 segundos!
Worker 0 started Worker 1 started Worker 2 started Worker 3 started ==================== Worker 1 finished ==================== Worker 2 finished ==================== Worker 3 finished ==================== Worker 0 finished multiProcessed: 5.266s Processing results: [ 4971422688.053512, 4989646323.157899, 4999088030.661542, 5008034869.924775 ]
¡Nuestro script ha funcionado cuatro veces más rápido! ¿No es eso magnífico?
Con gran curiosidad, ejecuté ambos scripts en una computadora bendecida con un procesador de 4 núcleos, esperando ver cómo se desarrollaba la magia:
El artista solista, nuestro guión de un solo subproceso, procesó diligentemente los datos en 25,8 segundos .
¡El equipo repleto de energía, nuestro script de subprocesos múltiples, lo eliminó del parque en solo 5.2 segundos !
Contempla el poder del multiprocesamiento: ¡más que cuadruplicar la velocidad de los cálculos!
Estos marcados contrastes resaltan cómo el multiprocesamiento puede amplificar drásticamente las capacidades computacionales de su máquina y reducir el tiempo de ejecución.
Nuestra emocionante exploración pinta una imagen vívida de cómo el multiprocesamiento puede acelerar las tareas computacionales en Node.js. Liberar su código en cada núcleo de procesador ofrece un salto tangible en el rendimiento, ¡similar a pasar de caminar a teletransportarse!
Definitivamente vale la pena agregar esta flecha a su carcaj de codificación y experimentar con este enfoque en sus proyectos. Y con la llegada de Worker Threads en Node.js, implementar el multiprocesamiento se ha convertido en un juego de niños.
¿Tienes un subidón de adrenalina leyendo esto? ¡Siéntase libre de compartir sus propias aventuras con el multiprocesamiento en Node.js en los comentarios a continuación! Sigamos desentrañando juntos los misterios de la codificación de alta velocidad.