Das Unangenehmste an NodeJS ist seine Single-Threaded-Natur. Es kann nicht viele Dinge tun und seine Leistung ist für CPU-intensive Szenarien nicht stark genug. Ich wollte schon lange einige Lösungen im Rahmen des JavaScript-Sprachframeworks finden, um die Probleme der Unfähigkeit, Threads zu bedienen, und der schlechten Leistung zu lösen. Die Lösung, die mich am meisten beeindruckt hat, waren Fasern, aber unabhängig von Fasern oder anderen Lösungen ist die Fadenbedienung immer noch sehr umständlich und zwingt das Pferd von hinten Bedenken Sie, dass JavaScript von Natur aus nicht lösbar ist. Das Peinlichste ist, dass die Nachrichtenübermittlung zwischen Threads im JavaScript-Sprachframework häufig sehr eingeschränkt ist und Objekte nicht wirklich gemeinsam genutzt werden können.
Die Add-on-Methode von nodejs ist zweifellos hervorragend, mit extrem hoher Flexibilität, vollständigen Funktionen und der Leistung von nativem Code. Einfach ausgedrückt ermöglicht es NodeJS, das C/C-Modul direkt aufzurufen, bei dem es sich um einen gemischten Entwicklungsmodus aus Javascript und Native handelt. Das ist eine gute Sache, warum nicht nutzen? Addon sollte ein großes Thema sein. Ich möchte heute nicht zu ausführlich darüber sprechen. Implementieren Sie dann eine Schlaffunktion und betrachten Sie diese als Einstieg.
schlafen
Warum kann JavaScript keinen echten Schlaf implementieren? Die Schlafmethode registriert ein Signal beim Betriebssystemkernel und sendet nach einer bestimmten Zeit ein Wecksignal, während der Thread selbst hängt. Wenn der Thread schläft (1000), bedeutet dies im Wesentlichen, dem Betriebssystem mitzuteilen: Weisen Sie mir innerhalb von 1000 ms keine CPU-Zeit zu. Daher kann der Ruhezustand sicherstellen, dass der Thread beim Anhalten keine CPU-Ressourcen mehr beansprucht. JavaScript läuft in einem einzelnen Thread und hebt das Thread-Konzept auf. Natürlich gibt es keine Möglichkeit, den Haupt-Thread anzuhalten und zu unterbrechen.
Einige Leute werden auch versuchen, Javascript zu verwenden, um den Schlaf zu implementieren, zum Beispiel:
Dabei wird eine leere Schleife verwendet, um die Ausführung des Hauptprozesses zu blockieren, um den Schlaf zu implementieren, der offensichtlich weit vom echten Schlaf entfernt ist.
Was wäre, wenn wir einen echten Schlaf einführen würden?
Umgebungsvorbereitung
Entwicklungsumgebung
Einige meiner Blogs haben es schon einmal gesagt, daher werde ich es hier weglassen: node.js npm, python 2.7, visual studio/x-code.
Kompilierungstools
Das Kompilierungstool muss Node-Gyp verwenden. Wenn Node-Gyp nicht im Lieferumfang enthalten ist, führen Sie bitte Folgendes aus:
Geben Sie den Projektordner ein und führen Sie npm init aus, um das Projekt zu initialisieren. Um nodejs mitzuteilen, dass wir ein Add-on erstellen möchten, müssen wir package.json hinzufügen:
Schauen Sie sich einfach die drei beteiligten Konfigurationselemente an:
1.target_name: Gibt den Namen des Ausgabemoduls an.
2.Quellen: Gibt den Quellcodepfad an, der kompiliert werden muss. Dies ist ein Array.
3.include_dirs: Gibt die Verzeichnisse an, die während des Kompilierungsprozesses verwendet werden sollen. Die Header-Dateien in diesen Verzeichnissen können in der Vorkompilierungsanweisung #include durchsucht werden. Hier wird eine ganz besondere Schreibweise verwendet, anstatt den Pfad als String-Konstante anzugeben. Wir werden später über die Nan-Bibliothek sprechen Schauen Sie sich an, was dieser Befehl ausgibt: node_modulesnan. Es stellt sich heraus, dass dieser Befehl bedeutet, den Pfad der Nan-Bibliothek zurückzugeben.
C-Kodierung
OK, jetzt, da der Quellcode hello.cc konfiguriert wurde, erstellen Sie eine solche Datei. Es gibt ein Problem, an das wir im Voraus erinnern müssen. Das von uns geschriebene C-Modul wird letztendlich von der v8-Engine verwendet, sodass die API, die Schreibmethode usw. durch die v8-Engine eingeschränkt werden. Verschiedene Versionen von NodeJS verwenden tatsächlich unterschiedliche Versionen der v8-Engine, was bedeutet, dass es schwierig ist, einen Satz C-Code zu verwenden, um verschiedene Versionen von NodeJS zu erfüllen (bezogen auf den Kompilierungsprozess). Nach Abschluss der Kompilierung sollte dies möglich sein Ja, Github kann keine Binärbibliotheken hochladen, daher kann npm Binärbibliotheken direkt hochladen und der Kompilierungsschritt ist relativ gering.
Knoten 0.11 und höher:
unter Verwendung des Namespace v8;
void SleepFunc(const v8::FunctionCallbackInfo
Isolate* Isolate = Isolate::GetCurrent();
HandleScope-Bereich (isoliert);
double arg0 = args[0] -> NumberValue();
Sleep(arg0);
}
void Init(Handle
NODE_MODULE(Hallo, Init);
Knoten 0.10 und niedriger:
unter Verwendung des Namespace v8;
Handle
HandleScope-Bereich;
double arg0 = args[0] -> NumberValue();
Sleep(arg0);
Gibt Scope.Close(Undefiniert());
zurück
}
void Init(Handle
NODE_MODULE(Hallo, Init);
Man erkennt, dass die Veränderungen noch recht groß sind. Es wäre toll, wenn diese Unterschiede irgendwie abgeschirmt werden könnten. Ich schreibe so viel, nur um Ihnen zu sagen, dass es einen Weg gibt. Es ist Zeit, die Nan-Bibliothek zu besuchen.
nan
Denken Sie daran, dass wir in binding.gyp den Pfad der Nan-Bibliothek eingeführt haben, der hier verwendet werden soll. Wozu dient die Nan-Bibliothek? Es bietet eine Abstraktionsebene, die die Syntaxunterschiede zwischen NodeJS 0.8, NodeJS 0.10, NodeJS 0.12 und dem Add-on vor io.js abschirmt. Lob!
Zuerst installieren: npm install --save nan und sehen, wie die gleiche Funktion nach der Verwendung von nan implementiert wird:
NAN_METHOD(Sleep){
NanScope();
Double arg0=args[0]->NumberValue();
Sleep(arg0);
NanReturnUndefined();
}
void Init(Handle
NODE_MODULE(Hallo, Init);
Was Sie wissen müssen, ist das Nan-Set. Was das v8-Set betrifft, müssen Sie nicht darauf achten.
Blick von unten nach oben:
Dieser Satz definiert den Eingang des Add-ons. Beachten Sie, dass der erste Parameter mit unserem Zielnamen in binding.gyp übereinstimmen muss. Der zweite Parameter ist die Eingabefunktion des Addons.
Dieser Code ist die Eingabemethode des Add-ons. Es erhält zwei Parameter, nämlich Exporte und Modul. Im obigen Beispiel wird der zweite Parameter weggelassen. Wenn das Modul ein Objekt bereitstellt, können Sie den Schlüsselwert, der für Exporte bereitgestellt werden soll, wie im Beispiel direkt angeben. Wenn es speziell ist und nur einen Wert oder eine Funktion bereitstellt, müssen Sie den zweiten Parameter verwenden, ähnlich wie im Beispiel NODE_SET_METHOD(module, "exports", foo); In diesem Beispiel bedeutet es, ein solches Modul auszugeben:
Schlaf ist eine Funktion. Werfen wir einen Blick auf die Definition von Schlaf:
Tatsächlich werden die von Javascript übergebenen Parameter gelesen, in einen Doppeltyp konvertiert und dann die Schlafmethode von c aufgerufen.
Addon kompilieren
Jetzt beginnen wir mit der Zusammenstellung dieses Moduls. Führen Sie zunächst „node-gyp configure“ aus, um den Build vorzubereiten. Dadurch werden ein Build-Ordner und einige Dateien generiert. Führen Sie als Nächstes „node-gyp build“ aus, um die Kompilierung zu starten. In diesem Beispiel wird schließlich eine hello.node-Datei im Verzeichnis /build/Release/ generiert, bei dem es sich um das Add-on-Modul handelt, auf das schließlich Javascript verweisen kann.
Wenn später Änderungen am C-Code vorgenommen werden, ist es nicht erforderlich, „node-gyp configure“ auszuführen, sondern einfach „node-gyp build“ direkt auszuführen.
nodejs verwenden
Erstellen Sie eine index.js und sehen Sie, wie Sie dieses Modul verwenden:
console.log(neues Datum);
schlafen(1000);
console.log(neues Datum);
// Ergebnis
// Mittwoch, 4. März 2015, 14:55:18 GMT 0800 (China Standard Time)
// Mittwoch, 4. März 2015, 14:55:19 Uhr GMT 0800 (China Standard Time)
C'est très simple, c'est exactement la même chose que d'utiliser des fonctions javascript ordinaires.
À ce stade, les points techniques que je souhaite partager dans cet article ont été expliqués. Mais... en quoi est-ce différent de la méthode proposée au début ? Je ne prendrai pas de captures d'écran, expliquez simplement les résultats directement :
Étant donné que la méthode complémentaire utilise la suspension des threads, il n'y aura théoriquement aucune modification de l'utilisation du processeur ni de la mémoire, et les résultats le vérifient également. Regardons la façon dont les boucles JavaScript simulent le sommeil. Puisque la boucle est toujours en cours d'exécution, il est compréhensible que la mémoire augmente un peu. Ce n'est pas grave si l'on considère l'utilisation du processeur de 25 %, cela semble tout à fait acceptable. Est-ce vraiment le cas ? Le moment est venu que la vérité soit révélée. Le processeur de l'ordinateur portable que j'ai testé est double cœur et quatre threads. Combiné avec une utilisation du processeur de 25 %... l'un des threads double cœur et quatre threads pourrait-il être occupé par cette veille ? En fait, j'ai constaté qu'aucun thread n'était verrouillé pendant cette période, mais ce n'est pas le résultat de JavaScript, mais le mérite d'Intel Hyper-Threading. Parce qu'il est dit qu'il s'agit de quatre threads, l'essentiel est que les deux cœurs de traitement ne peuvent être que des threads doubles, mais le processeur fait un petit tour de coupe de tranche de temps. Par exemple, le noyau cpu01 est divisé en t0 et t2. Supposons que dans un tick après n ticks (cycle de planification), la tâche sera affectée à t0, puis au tick suivant, la tâche sera affectée à t2. Par conséquent, sur une échelle de temps relativement longue (par rapport à la période de planification), la durée d’exécution d’une tâche à t0 et t2 est fondamentalement la même. La situation présentée est donc que le processus nodejs n'occupe pas t0 ou t2 à 100 %, mais occupe respectivement environ 50 %. Étant donné que la planification des processus de Windows est relativement complexe, l'utilisation du processeur fluctue considérablement. On peut prédire que si un processeur double cœur et double thread est utilisé pour traiter ce script, l'utilisation du processeur atteindra 50 % et un cœur sera bloqué. S'il est traité par un processeur monocœur, le processeur passera soudainement à 100 %.
Il semble que la section CPU parle un peu trop, et la section hyper-threading n'est que de la spéculation.