Workers
Los workers mejor conocidos como “hilos” se encargan de generar un procesos al igual que child_process y cluster, la diferencia es que los workers comparten el mismo espacio de memoria y por lo tanto son más eficientes en consumo de recursos, esto significa que los hijos se pueden comunicar entre ellos, algo que no pasa con los casos anteriores que tienen su propio espacio de memoria.
__Parent___ __parent___
| process | | process |
| 1 thread| | N workers|
| 1 event | | N event |
| loop | | loop |
|__________| |__________|
Si bien crear un worker es mucho más optimo que crear un fork, es recomendable usar un pool de workers el cual usa un patrón para manejar la concurrencia, usualmente una cola (ver workerpool).
Hilos
Cuando creamos un worker lo podemos hacer en un solo archivo, en este ejemplo vemos que nuestro mismo archivo crea un proceso principal en el if y ese mismo archivo se transforma en un hilo en el else.
const { Worker, isMainThread } = require('worker_threads');
if (isMainThread) {
// This re-loads the current file inside a Worker instance.
new Worker(__filename);
} else {
console.log('Inside Worker!');
console.log(isMainThread);
}
Si deseamos comunicar el proceso padre con el hijo debemos usar el metodo postMessage para enviar datos y parentPort para que el hijo se comunique con el padre.
const { Worker, isMainThread, parentPort } = require('worker_threads');
if (isMainThread) {
const worker = new Worker(__filename);
// listening child income messages
worker.once('message', (message) => {
console.log(`worker-${worker.threadId} send: ${message}`);
});
// main process sending message to thread
worker.postMessage('Hello, world!');
} else {
// When a message from the parent thread is received, send it back:
parentPort.once('message', (message) => {
console.log(`main send: ${message}`);
parentPort.postMessage(message);
});
}
Por medio de MessageChannel podemos comunicar entre hilos o utilizar canales de comunicación con una sola responsabilidad.
const assert = require('assert');
const {
Worker, MessageChannel, MessagePort, isMainThread, parentPort
} = require('worker_threads');
if (isMainThread) {
const worker = new Worker(__filename);
const worker2 = new Worker(__filename);
// create subchannels to facilitate separation of concerns
const { port1, port2 } = new MessageChannel();
// can communicate between workers
worker.postMessage({ port: port1, id: worker.threadId }, [port1]);
worker2.postMessage({ port: port2, id: worker2.threadId }, [port2]);
} else {
parentPort.once('message', (value) => {
const id = value.id;
value.port.postMessage(`the worker ${id} is sending this`);
value.port.on('message', (value) => {
console.log(`worker ${id} received:`, value);
});
});
}