02.122011

node.js: CPU intensive Berechnungen ohne die Event Loop zu blockieren

Wenn ein node.js Programm viel auf der CPU rechnen muss ist für die Dauer dieser Berechnungen die Event Loop blockiert. Folgendes Programm, welches sich nach 10s beenden sollte, funktioniert deswegen nicht wie erwartet:

setTimeout(function() { process.exit(0); }, 10000);
for(;;) {
  doSomething();
}

Die Timeout Funktion wird nie ausgeführt, weil die for-Schleife die Kontrolle niemals an die Event Loop zurückgibt.

Um das Problem zu umgehen muss die for-Schleife die Kontrolle bei jeder Iteration kurzzeitig an die Event Loop abgeben. Hierzu wird der Aufruf in eine Funktion geschachtelt, welche die eigentliche Funktion ausführt und sich nach einem Timeout von 1ms selbst aufruft:

setTimeout(function() { process.exit(0); }, 10000);
function wrapper(fn) {
  fn();
  setTimeout(wrapper.bind(this, fn), 1);
}
wrapper(doSomething); 

Hierdurch ist gewährleistet das die Event Loop nicht blockiert und sich das Programm tatsächlich nach 10s beendet.

Noch ein Hinweis zur vermeintlichen Rekursion; es findet keine Rekursion statt, da wrapper() nach dem ersten Aufruf immer von der Event Loop aus aufgerufen wird.