O JavaScript foi projetado inerentemente como uma fera de thread único. No entanto, nos terrenos selvagens da computação, os predadores conhecidos como 'multiprocessamento' e 'processadores multi-core' estão esperando para serem domados, prontos para aumentar a execução de seu código a velocidades inéditas. 💪🚀
Eu ousei entrar nesta selva, colocar meu código no teste de sobrevivência final e emergir com resultados surpreendentes. 🏆 Agora é a sua vez de se juntar a mim nesta fascinante missão. Vamos nos aprofundar no enigma do multiprocessamento em Node.js , munidos de exemplos de código fascinantes e iluminando com a tocha 🔦 os frutos espetaculares de meus experimentos. 🍎🍏
Prepare-se para embarcar nesta aventura movida a adrenalina de turbinar o desempenho do JavaScript por meio da magia do multiprocessamento! Aperte o cinto e prepare-se, pois estamos prestes a entrar no reino hipnotizante da codificação de alta octanagem.
Antes de nos aventurarmos muito fundo, vamos nos equipar com algumas ferramentas confiáveis. Criaremos algumas funções auxiliares para simular o frequentemente árduo trabalho computacional. Vamos criar um novo artefato, um arquivo chamado utils.js
, e inscrever esses encantamentos essenciais nele.
// 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, };
A execução em um único thread representa uma abordagem trabalhadora e confiável para a solução de problemas. A versão de thread único do script pode ser descrita visualmente como tal. O código da versão single-threaded é bastante direto. Criamos dados e os enviamos para processamento.
// sync.js const { generateRandomData, processData } = require("./utils"); const data = generateRandomData(30000); console.time("single-thread. Time:"); processData(data); console.timeEnd("single-thread. Time:");
Iniciamos o script com o comando: node sync.js
Esperamos... e esperamos... e esperamos...
E após toda essa espera, recebemos uma mensagem indicando o tempo de execução do script.
single-thread. Time:: 25.888s
Essa abordagem é adequada para a maioria dos casos. Mas há um soluço. Quem, em sã consciência, adora a arte de esperar? Para superar esse atraso agonizante, devemos aproveitar todo o poder de fogo de nossos computadores! Afinal, a maioria dos computadores modernos vem carregada com mais de um único núcleo de CPU!
Então, por que devemos deixar esses núcleos adicionais ficarem ociosos quando eles podem estar processando números e sobrecarregando nossa execução de código ? É hora de iluminar aqueles gigantes adormecidos e liberar o poder bruto do multiprocessamento! Vamos mergulhar!
Adotando a abordagem multiprocessada, podemos alavancar vários núcleos de nossa CPU, impulsionando o desempenho de nosso script várias vezes. O processo de operação do nosso código multiprocessado pode ser visualizado com este diagrama.
Em essência, estamos simplesmente particionando um conjunto de dados considerável em segmentos e atribuindo cada segmento para processamento a um núcleo de CPU discreto.
Crie um arquivo intitulado multi-process.js
e preencha-o com o seguinte conteúdo.
// 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 a orquestração de um processo de trabalho solitário na sinfonia da manipulação de dados multiprocessados em Node.js.
Em resumo, aqui está o que está acontecendo:
O trabalhador recebe dados e seu número do processo principal via process.on('message')
.
A função processData
realiza cálculos na porção de dados atribuída a este trabalhador.
O resultado é enviado de volta ao processo principal via `process.send()``.
O trabalhador termina com o código 0 via process.exit()
.
Inicie o script com o comando: node multi-process.js
Segure firme para o turbo boost...
E chegamos à conclusão de que o código funcionou em 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 ]
Nosso script funcionou quatro vezes mais rápido! Isso não é magnífico?
Com muita curiosidade, executei os dois scripts em um computador equipado com um processador de 4 núcleos, esperando para testemunhar o desenrolar da mágica:
O artista solo, nosso script de thread único, processou diligentemente os dados em 25,8 segundos .
A equipe poderosa, nosso script multi-threaded, o tirou do parque em apenas 5,2 segundos !
Contemple o poder do multiprocessamento – mais do que quadruplicar a velocidade dos cálculos!
Esses contrastes gritantes destacam como o multiprocessamento pode ampliar drasticamente os recursos computacionais de sua máquina e reduzir o tempo de execução.
Nossa emocionante exploração mostra um quadro vívido de como o multiprocessamento pode turbinar as tarefas computacionais no Node.js. Liberar seu código em cada núcleo do processador oferece um salto tangível no desempenho, semelhante à mudança da caminhada para o teletransporte!
Definitivamente, vale a pena adicionar esta seta à sua aljava de codificação e experimentar essa abordagem em seus projetos. E com o advento dos Worker Threads no Node.js, a implementação do multiprocessamento tornou-se muito fácil.
Sentiu uma descarga de adrenalina lendo isso? Sinta-se à vontade para compartilhar suas próprias aventuras com multiprocessamento em Node.js nos comentários abaixo! Vamos continuar a desvendar os mistérios da codificação de alta velocidade juntos.