Tengo un servidor Node que crea un proceso secundario con el fork()
uso de IPC. En algún momento, el niño envía los resultados al padre a aproximadamente 10Hz como parte de una tarea de larga duración. Cuando la carga útil que se pasa process.send()
es pequeña, todo funciona bien: cada mensaje que envío se recibe ~ inmediatamente y el padre lo procesa.
Sin embargo, cuando la carga útil es 'grande' (no he determinado el límite de tamaño exacto) en lugar de ser recibida de inmediato por el padre, todas las cargas se envían primero, y solo una vez que el niño realiza su tarea de larga duración, el padre recibe y procesar los mensajes.
tl; dr visual:
Bueno (sucede con poca carga útil):
child: send()
parent: receive()
child: send()
parent: receive()
child: send()
parent: receive()
...
Malo (sucede con gran carga útil):
child: send()
child: send()
child: send()
(repeat many times over many seconds)
...
parent: receive()
parent: receive()
parent: receive()
parent: receive()
...
- ¿Es esto un error? (Editar: el comportamiento solo ocurre en OS X, no en Windows o Linux)
- ¿Hay alguna forma de evitar esto, aparte de tratar de mantener pequeña mi carga útil de IPC?
Edición 2 : el siguiente código de muestra utiliza el contador de tiempo y de iteración para seleccionar cuándo enviar una actualización. (En mi código actual también es posible enviar una actualización después de n iteraciones, o después de que el ciclo logre ciertos resultados). Como tal, reescribir el código para usar setInterval
/ en setTimeout
lugar de un ciclo es un último recurso para mí, ya que me requiere para eliminar características.
Editar : Aquí hay un código de prueba que reproduce el problema. Sin embargo, solo se reproduce en OS X, no en Windows o Linux:
server.js
const opts = {stdio:['inherit', 'inherit', 'inherit', 'ipc']};
const child = require('child_process').fork('worker.js', [], opts);
child.on('message', msg => console.log(`parent: receive() ${msg.data.length} bytes`, Date.now()));
require('http').createServer((req, res) => {
console.log(req.url);
const match = /\d+/.exec(req.url);
if (match) {
child.send(match[0]*1);
res.writeHead(200, {'Content-Type':'text/plain'});
res.end(`Sending packets of size ${match[0]}`);
} else {
res.writeHead(404, {'Content-Type':'text/plain'});
res.end('what?');
}
}).listen(8080);
trabajador.js
if (process.send) process.on('message', msg => run(msg));
function run(messageSize) {
const msg = new Array(messageSize+1).join('x');
let lastUpdate = Date.now();
for (let i=0; i<1e7; ++i) {
const now = Date.now();
if ((now-lastUpdate)>200 || i%5000==0) {
console.log(`worker: send() > ${messageSize} bytes`, now);
process.send({action:'update', data:msg});
lastUpdate = Date.now();
}
Math.sqrt(Math.random());
}
console.log('worker done');
}
Aproximadamente alrededor de 8k el problema ocurre. Por ejemplo, al consultar http://localhost:8080/15
vshttp://localhost:8080/123456
/15
worker: send() > 15 bytes 1571324249029
parent: receive() 15 bytes 1571324249034
worker: send() > 15 bytes 1571324249235
parent: receive() 15 bytes 1571324249235
worker: send() > 15 bytes 1571324249436
parent: receive() 15 bytes 1571324249436
worker done
/123456
worker: send() > 123456 bytes 1571324276973
worker: send() > 123456 bytes 1571324277174
worker: send() > 123456 bytes 1571324277375
child done
parent: receive() 123456 bytes 1571324277391
parent: receive() 123456 bytes 1571324277391
parent: receive() 123456 bytes 1571324277393
Experimentado en Nodo v12.7 y v12.12.
run()
tiene un while
bucle? ¿Estás sugiriendo que cambiar eso a setInterval()
resolverá mi problema? Para responder a la pregunta, creo que se está preguntando: uso un while
bucle porque esa función es el único propósito de este proceso de trabajo y (con pequeñas cargas útiles de IPC) no causó ningún problema que pudiera ver.
setInterval()
libera el ciclo de eventos para realizar E / S en segundo plano. No estoy diciendo que definitivamente resolverá este problema, pero parece una elección extraña escribirlo de la manera que lo ha hecho, solo porque puede hacerlo.
setTimeout()
o setInterval()
. El cambio aquí es trivial.
setInterval()
?