Ich habe einen Knotenserver, der mit fork()
IPC einen untergeordneten Prozess erstellt . Irgendwann sendet das Kind die Ergebnisse im Rahmen einer lang laufenden Aufgabe mit etwa 10 Hz an die Eltern zurück. Wenn die an übergebene Nutzlast process.send()
klein ist, funktioniert alles einwandfrei: Jede von mir gesendete Nachricht wird sofort empfangen und vom übergeordneten Element verarbeitet.
Wenn die Nutzlast jedoch "groß" ist - ich habe die genaue Größenbeschränkung nicht festgelegt -, werden alle Nutzdaten zuerst gesendet, anstatt sofort vom Elternteil empfangen zu werden, und erst wenn das Kind seine langfristige Aufgabe erledigt hat, erhält das Elternteil und verarbeiten Sie die Nachrichten.
tl; dr visuell:
Gut (passiert mit kleiner Nutzlast):
child: send()
parent: receive()
child: send()
parent: receive()
child: send()
parent: receive()
...
Schlecht (passiert mit großer Nutzlast):
child: send()
child: send()
child: send()
(repeat many times over many seconds)
...
parent: receive()
parent: receive()
parent: receive()
parent: receive()
...
- Ist das ein Fehler? (Bearbeiten: Verhalten tritt nur unter OS X auf, nicht unter Windows oder Linux)
- Gibt es eine Möglichkeit, dies zu vermeiden, außer zu versuchen, meine IPC-Nutzlast klein zu halten?
Bearbeiten 2 : Der folgende Beispielcode verwendet sowohl den Zeit- als auch den Iterationszähler, um auszuwählen, wann ein Update gesendet werden soll. (In meinem eigentlichen Code ist es auch möglich, ein Update nach n Iterationen oder nachdem die Schleife bestimmte Ergebnisse erzielt hat zu senden .) Daher ist ein Umschreiben des zu verwendenden Codes setInterval
/ setTimeout
anstelle einer Schleife ein letzter Ausweg für mich, da dies mich erfordert Funktionen entfernen.
Bearbeiten : Hier ist Testcode, der das Problem reproduziert. Es wird jedoch nur unter OS X reproduziert, nicht unter Windows oder 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);
worker.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');
}
Gegen 8k tritt das Problem auf. Zum Beispiel bei der Abfrage von http://localhost:8080/15
vs.http://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
Erfahrung sowohl auf Node v12.7 als auch auf v12.12.
run()
eine while
Schleife darin ist? Schlagen Sie vor, dass das Umschalten auf setInterval()
mein Problem löst? Um die Frage zu beantworten, die Sie meiner Meinung nach stellen: Ich verwende eine while
Schleife, da diese Funktion der einzige Zweck dieses Arbeitsprozesses ist und (bei kleinen IPC-Nutzdaten) kein Problem verursacht hat, das ich sehen konnte.
setInterval()
wird die Ereignisschleife freigegeben, um E / A im Hintergrund auszuführen. Ich sage nicht, dass es dieses Problem definitiv lösen wird, aber es scheint eine seltsame Wahl zu sein, es so zu schreiben, wie Sie es haben, nur weil Sie es können.
setTimeout()
oder setInterval()
. Die Änderung hier ist trivial.
setInterval()
.