C++ mit node.js

Standard

Ich habe mich die letzten Wochen damit beschäftigt, auszuloten was mit der C++-Schnittstelle in Node.js (Genannt „Addon“) möglich ist.

Dazu habe ich ein kleines Ruby-on-Rails-Projekt mit Node.js reimplementiert. Ich war ziemlich begeistert, wie schnell man zu einem lauffähigen Prototypen kommt. Mit JavaScript habe ich mich anfangs schwer getan. Wenn man aus der Welt einer Multiparadigmen-Sprache wie C++ kommt kommt, fühlt sich JavaScript beengend an. Sicher ist dieses Callback-Konzept eine nette Geschichte. Jedoch lassen sich nicht alle Aufgaben mit diesem Ansatz am elegantesten lösen. Wer mal bei Google nach „node.js callback hell“ sucht, wird ein paar interessante Artikel finden. JavaScript hat aber unbestritten seine Fans, wahrscheinlich sogar mehr Fans als C++.

Nach einer Weile bin ich bei meinem Portierungsprojekt auf ein Problem gestoßen. Es betraf indirekt die fehlende Fähigkeit zu Nebenläufigkeit in Node.js. Nebenläufigkeit kann ziemlich kniffelig werden. Vielleicht war das auch der Grund warum man bei Node.js darauf verzichtet hat, übrigens genauso wie bei Ruby-on-Rails.

Eine Herausforderung war, dass mein Programm verschiedene Daten aus unterschiedlichen Quellen bezog. Da war die Konfiguration des Programms selbst, die sich im Betrieb ändern könnte und in einer Textdatei gespeichert würde. Die Änderungen sollten zur Laufzeit gelesen werden können, ohne die Applikation neu starten zu müssen. Eine weite Datenquelle sind die Verbindungsdaten der Telefonanlage, die abgefragt wird. Die dritte Datenquelle sind Zugverbindungen, die über eine externe Website eingeholt werden. Als Viertes wird vom Programm „fortune cookie“ noch ein „Spruch des Tages“ geholt.

Was ich natürlich nicht wollte, war das all diese Datenquellen mit jedem Browser-Request neu abgefragt würden. Ich präferierte den Weg, die Daten im RAM zu cachen. Deshalb mochte ich auch keine temporäre Daten verwenden, die ich immer wieder von der Festplatte auslese und damit unnötigen I/O-Operationen produziere. Darüber hinaus war der Refrash-Interval für alle Datenquellen unterschiedlich:

  • Die Konfiguration wollte ich ereignisbasiert auslesen, wenn sie geändert wurde
  • Die Telefonanlage sollte alle 5 Sekunden abfragt werden
  • Die Zugverbindungen sollten einmal in der Minute abgefragt werden
  • Der „fortune cookie“ sollte einmal am Tag erneuert werden

Über Google fand ich den Befehl „fs.watchFile(filename, [options], listener)“ (http://nodejs.org/api/fs.html#fs_fs_watchfile_filename_options_listener), um Änderungen an Dateien zu beobachten. Eine Änderung löst einen zu definierenden Callback aus. Also genau das, was ich für meine Konfiguration brauchte.

Ich suchte nach einem Befehl, mit dem ich ein Callback in einem bestimmten Intervall aufrufen lassen kann. Ich fand recht schnell die setInterval()-Methode und war fast begeitert, wie einfach man Probleme mit Node.js (bzw. JavaScript) lösen kann. Jedoch verhielt sich setInterval() nicht ganz so, wie ich es erwartete. Ich schrieb in mein Node.js-Code:


setInterval( getPhonData, (1000 * 5 ) );
setInterval( getTrainData, (1000 * 60 ) );
setInterval( getFortuneCookie, (1000 * 60 * 60 * 24) );

Jeder Callback wurde einmal aufgerufen und dann war Schluss. Wenn ich den t3n-Artikel vom 20.07.2014 schon gekannt hätte, wäre ich schneller darauf gekommen, was das Problem war. Mit jedem setInterval-Aufruf setzt man nicht einen neuen (eigenständigen) Timer sondern, man überschreibt den zuvor gesetzten. Somit kann man nur einen Timer haben. Man kann zwar ein bisschen mit Worker tricksen, die Möglichkeiten sind aber beschränkt. Es gibt keine vollwertigen Threads, die sich ihre Ressourcen teilen können.

Das war für mich der Anlass, mich an ein C++-Addon für Node.js zu versuchen. Ich wollte setInterval() als Multi-Threading-Variante implementieren. Um es gleich vorweg zu nehmen: ich bin gescheitert. Man findet im Web einige nette „Hallo-Welt“-Beispiele für Node.js-Addons in C++. Aber in einem Addon mehrere Threads zu starten und zu verwalten, ist dann doch was anderes, als ein „hello world“ auf die Konsole zu schreiben.

Zu den Faktoren, die bei der Aufgabenstellung hinderlich waren, zählt dass ich keine Node.js Mailingliste gefunden habe. Es gibt dutzende Foren und Mailinglisten für PHP und Ruby (deutsch/englisch), aber für Node.js sieht es mau aus. Es gibt eine Goole-Gruppe, die aber auch – dafür das sie die einzige ihrer Art ist – relativ wenig Aktivitäten hat. Die Fehlermeldungen von Node.js waren wenig hilfreich. Das Programm beendet sich einfach kommentarlos. Der Debugging-Modus hat mir auch kaum geholfen, denn man sieht nicht, was in dem Addon passiert.

Dabei ist mir noch mal deutlich geworden, das ein C++-Addon das sich übersetzen lässt, leider noch lange nicht lauffähig sein muss. Der Gluten-Code ist eine sehr lockere Bindung zwischen JavaScript und C++. Nur weil der GCC nicht meckert, muss das nicht heißen, dass JavaScript die C++-Klasse auch wirklich erreicht. Ein C++-Entwickler der wie ich, die Strenge eines C++-Compilers schätzt, wird in seiner Begeisterung etwas gedämpft werden.

Unangenehm fand ich auch, dass man gezwungen wird in der Wrapper-API Zeiger statt Referenzen zu verwenden, das ich wegen der damit verbundenen Risiken bei der Speicherverwaltung gerne vermeide. Richtige Typsicherheit gibt es natürlich auch nicht. Jeder übergebene Wert sollte deshalb besser überprüft und mit Fehlerbehandlungen versehen werden.

Es gab aber auch positive Erfahrungen. So funktionierte die C++11-Unterstützung problemlos, was die Thread-Programmierung erleichtert hätte, wenn es sie gegeben hätte. Auch das Node.js eigene Build-Tool (gyp) fand ich vom Konzept her nett. Mir gefiel besonders, dass die Konfiguration mit Json erfolgt und keine kryptische-esoterische Macro-Sprache gelernt werden muss.

Mein Gesamteindruck ist, dass die Schnittstelle zwischen JavaSript und C++ in Node.js für die JavaScrip-Programmierer wesentlich komfortabler ist als für die C++-Entwickler. Die JavaScript-Programmierer können das Interface (den Wrapper der C++-Klassen und Methoden) verwenden, wie sie es von ihrer Sprache gewohnt sind. Die C++-Entwickler müssen sich hingegen mit einem nicht selbsterklärenden Konzept mit wenig Dokummentation auseinandersetzen. Zudem liegt die gesamte Last für die API-Sicherheit bei den C++-Programmierern. Sie müssen dafür sorgen, dass Ausnahmen abgefangen werden sowie dass Typen und Werte geprüft werden. Das dürfte die Attraktivität von Node.js für C++-Entwickler leider senken.

Advertisements

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s