Heim >Web-Frontend >js-Tutorial >Beispiele für Methoden zur Verwendung von Multithread-Programmierung in nodejs_node.js
In meinem vorherigen Blog-Beitrag Sagen Sie nicht, dass es unmöglich ist, implementieren Sie Sleep in NodeJS , ich habe Ihnen die Verwendung des NodeJS-Add-Ons vorgestellt. Das heutige Thema ist immer noch Add-on. Erkunden Sie weiterhin die Fähigkeiten von C/C und gleichen Sie die Schwächen von NodeJS aus.
Ich habe die Leistungsprobleme von NodeJS schon oft erwähnt. Was die Sprache selbst betrifft, ist die Leistung von NodeJS zwar nicht so gut wie die der meisten statischen Sprachen, der Unterschied zu anderen dynamischen Sprachen ist jedoch nicht groß . Aber warum sagen wir oft, dass NodeJS nicht für CPU-intensive Szenarien geeignet ist? Denn aufgrund seiner Single-Threaded-Natur kann es die CPU für CPU-intensive Szenarien nicht vollständig ausnutzen. In der Informatik gibt es ein berühmtes Amdahl-Gesetz:
Gehen Sie davon aus, dass die Gesamtarbeitslast W in zwei Teile zerlegt werden kann: Ws, das nur seriell berechnet werden kann, und Wp, das eine parallele Berechnung ermöglicht. Dann kann beim parallelen Rechnen von p CPUs die Leistung durch Beschleunigungszeiten verbessert werden. Das Amdahlsche Gesetz beschreibt, was Parallelität bewirken kann und was nicht. Dies ist eine ideale Situation, die tatsächliche Situation wird viel komplexer sein. Beispielsweise führt die Parallelität wahrscheinlich zu Ressourcenkonflikten, die das Hinzufügen verschiedener Sperren erfordern, wodurch die Parallelität häufig in einem Wartezustand verbleibt und außerdem einen zusätzlichen Zeitaufwand für das Betriebssystem verursacht, um die Thread-Planung zu ändern, was die Ws erhöht. Wenn jedoch Wp in einer Aufgabe viel größer als Ws ist und mehrere CPU-Kerne verfügbar sind, ist die Leistungsverbesserung durch Parallelität beträchtlich.
Okay, zurück zu nodejs. Stellen wir uns ein Berechnungsszenario vor: Berechnen Sie die Anzahl der Primzahlen innerhalb von 4.000.000. Wenn dieses Szenario programmiert wird, werden hauptsächlich Divisionsoperationen verwendet und Operationen wie Speicher und Objekte sind nicht beteiligt. Theoretisch kann dadurch sichergestellt werden, dass NodeJS mit einer relativ hohen Geschwindigkeit ausgeführt wird und nicht zu weit hinter c zurückbleibt, was praktisch ist Vergleich.
Die Methode zum Finden von Primzahlen in JavaScript wurde in diesem Blog bereitgestellt, kopieren Sie sie direkt:
Schreiben Sie eine weitere C-Sprachversion:
bool zhishu(int num){
If (num == 1) {
return false;
}
Wenn (num == 2) {
return true;
}
for (int i = 2; i <= sqrt(num); i ) {
If (num % i == 0) {
return false;
}
}
Gibt true zurück;
};
In nodejs verwenden wir eine Schleife von 1 bis 4000000, um Primzahlen in der Sprache C abzurufen. Wir richten mehrere Threads ein und definieren die Anzahl als 4000000. Jeder Thread führt Folgendes aus: Wenn die Anzahl größer als 0 ist, wird sie entfernt Der Wert von count, berechnet, ob es sich um eine Primzahl handelt, und dekrementiert count um 1. Nach dieser Idee ist die Javascript-Version einfach zu schreiben:
für (j = 1; j < 4000000; j ) {
If(zhishu(j)){
Zählen ;
}
}
Die Hauptschwierigkeit ist die Multithread-Programmierung in der Sprache C. In den frühen Tagen von C/C wurde die Notwendigkeit paralleler Berechnungen nicht berücksichtigt, sodass die Standardbibliothek keine Multithreading-Unterstützung bot. Verschiedene Betriebssysteme haben normalerweise unterschiedliche Implementierungen. Um dieses Problem zu vermeiden, verwenden wir pthread zur Verarbeitung von Threads.
Laden Sie die neueste Version von pthread herunter. Da ich mit GYP nicht vertraut bin, habe ich lange gebraucht, um die Linkabhängigkeitsbibliothek zu reparieren. Am Ende bestand meine Methode darin, den Quellcode von pthread direkt im Projektverzeichnis abzulegen und pthread.c zum Quellcode hinzuzufügen Liste in binding.gyp, kompilieren Sie pthread einmal beim Kompilieren des Projekts. Die geänderte binding.gyp sieht folgendermaßen aus:
Natürlich ist meine Methode sehr mühsam. Wenn Sie nur Verweise auf die Bibliothek hinzufügen und Verzeichnisse in pthread einschließen, besteht keine Notwendigkeit, meine Methode zu verwenden.
Dann gehen wir auf alles zum Thema C/C-Multithreading ein und definieren eine Thread-Verarbeitungsfunktion:
void *thread_p(void *null){
int num, x=0;
tun{
pthread_mutex_lock(&lock);
num=count--;
pthread_mutex_unlock(&lock);
If(num>0){
If(zhishu(num))x ;
}sonst{
Pause;
}
}while(true);
std::cout<<' '<
}
Da der Compiler beim Kompilieren eine Kompilierungsoptimierung durchführt, wird eine Anweisung, wenn sie eindeutig nichts bewirkt und keinen Einfluss auf die Ausführung anderer Anweisungen hat, vom Compiler wegoptimiert. Im obigen Code habe ich den Code zum Zählen der Anzahl der Primzahlen hinzugefügt. Wenn nicht, würde er so aussehen:
Die Schreibmethode zum Hinzufügen von Add-ons wurde eingeführt. Wir erhalten einen Parameter von Javascript, der die Anzahl der Threads angibt, und erstellen dann eine bestimmte Anzahl von Threads in c, um den Primzahlabruf abzuschließen. Vollständiger Code:
int count=4000000;
pthread_t tid[MAX_THREAD];
pthread_mutex_t lock;
void *thread_p(void *null){
int num, x=0;
tun{
pthread_mutex_lock(&lock);
num=count--;
pthread_mutex_unlock(&lock);
if(num>0){
if(zhishu(num))x ;
}else{
Pause;
}
}while(true);
std::cout<<' '<
return null;
}
NAN_METHOD(Zhishu){
NanScope();
pthread_mutex_init(&lock,NULL);
double arg0=args[0]->NumberValue();
int c=0;
for (int j = 0; j < arg0 && j
}
for (int j = 0; j < arg0 && j
}
NanReturnUndefined();
}
void Init(Handle
NODE_MODULE(Hallo, Init);
phread_create可以创建线程,默认是joinable的,这个时候子线程受制于主线程;phread_join阻塞住主线程,等待子线程join, 直到子线程退出.如果子线程已退出, 则phread_join不会做任何事.所以对所有的线程都执行thread_join,可以保证所有的线程退出后才会例主线程继续进行.
完善一下nodejs脚本:
console.time("c");
zhishu_c(100);
console.timeEnd("c");
console.time("js");
var count=0;
für (j = 1; j < 4000000; j ) {
if(zhishu(j)){
zählen ;
}
}
console.log(count);
console.timeEnd("js");
Schauen Sie sich die Testergebnisse an:
Obwohl die Laufgeschwindigkeit von C/C im Single-Thread 181 % der von NodeJS beträgt, denken wir, dass dieses Ergebnis in dynamischen Sprachen immer noch sehr gut ist. Die Geschwindigkeitsverbesserung ist bei der Verwendung von Dual-Threads am deutlichsten, da mein Computer über eine Dual-Core-CPU mit vier Threads verfügt und derzeit möglicherweise zwei Kerne für die Verarbeitung verwendet werden. Die Geschwindigkeit erreicht das Maximum, wenn 4 Threads vorhanden sind. Zu diesem Zeitpunkt sollte die Grenze erreicht werden, die Dual-Core und vier Threads erreichen können. Wenn die Anzahl der Threads erhöht wird, kann die Geschwindigkeit nicht verbessert werden. Im obigen Amdahlschen Gesetz hat p die Obergrenze von 4 erreicht. Das Hinzufügen weiterer Threads erhöht die Planungszeit und Sperrzeit des Betriebssystemprozesses. Obwohl dadurch auch der Wettbewerb um die CPU-Zeit zunehmen wird, wird der Anstieg der Ws deutlicher sein und die Leistung sinken. Wenn Sie dieses Experiment auf einer Maschine im Leerlauf durchführen, sollten die Daten besser sein.
Aus diesem Experiment können wir den Schluss ziehen, dass die Effizienz bei CPU-intensiven Vorgängen erheblich verbessert wird, wenn die Berechnungen mehr Speicher, Zeichenfolgen, Arrays, Rekursion usw. erfordern (wird später überprüft), die Leistungsverbesserung ist sogar noch erstaunlicher. Gleichzeitig kann die rationelle Verwendung von Multithreads die Verarbeitungseffizienz effektiv verbessern, aber mehr Threads sind nicht immer besser. Sie müssen entsprechend den Bedingungen der Maschine konfiguriert werden.
Nodejs selbst ist zwar nicht gut darin, CPU-intensive Aufgaben zu bewältigen, aber mit der Erfahrung dieses Artikels denke ich, dass es nicht unmöglich ist, dieses Hindernis zu überwinden.