Heim >Web-Frontend >js-Tutorial >Eine Erklärung zum Blockieren und Nichtblockieren in Node.js

Eine Erklärung zum Blockieren und Nichtblockieren in Node.js

不言
不言nach vorne
2018-11-15 17:30:551935Durchsuche

Der Inhalt dieses Artikels befasst sich mit der Erklärung des Blockierens und Nichtblockierens in Node.js. Ich hoffe, dass er für Freunde hilfreich ist.

Blockierende vs. nicht blockierende Übersicht

Diese Übersicht erklärt den Unterschied zwischen blockierenden und nicht blockierenden Aufrufen in Node.js. Diese Übersicht bezieht sich auf die Ereignisschleife und libuv. Es sind keine Vorkenntnisse zu diesen Themen erforderlich, es wird jedoch ein grundlegendes Verständnis der JavaScript-Sprache und der Node.js-Rückrufmuster vorausgesetzt.

„E/A“ bezieht sich hauptsächlich auf die Interaktion mit der Festplatte und dem Netzwerk des von libuv unterstützten Systems.

Blockieren

Blockieren bedeutet, dass die Ausführung von anderem JavaScript im Node.js-Prozess warten muss, bis der Nicht-JavaScript-Vorgang abgeschlossen ist. Dies geschieht, weil die Ereignisschleife während des Blockierungsvorgangs nicht mit der Ausführung von JavaScript fortfahren kann auftritt.

In Node.js wird JavaScript, das eine schlechte Leistung aufweist, weil es CPU-intensiv ist und nicht auf Nicht-JavaScript-Vorgänge wie E/A wartet, im Allgemeinen nicht als Blockierung bezeichnet. Die Synchronisierungsmethode mit libuv in der Node.js-Standardbibliothek ist die am häufigsten verwendete Blockierungsoperation, und native Module verfügen möglicherweise auch über Blockierungsmethoden.

Alle I/O-Methoden in der Node.js-Standardbibliothek stellen nicht blockierende asynchrone Versionen bereit und akzeptieren Rückruffunktionen. Einige Methoden verfügen auch über entsprechende blockierende Methoden, deren Namen mit Sync enden.

Vergleichscode

Blockierende Methoden werden synchron ausgeführt und nicht blockierende Methoden werden asynchron ausgeführt.

Nehmen Sie das Dateisystemmodul als Beispiel. Hier ist eine Methode zum synchronen Lesen einer Datei:

const fs = require('fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read

Hier ist ein entsprechendes asynchrones Beispiel:

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
});

Erstes Beispiel Sieht einfacher aus als das zweite Beispiel, aber der Nachteil ist, dass die zweite Zeile die Ausführung von anderem JavaScript verhindert, bis die gesamte Datei gelesen ist. Beachten Sie, dass Sie in der synchronen Version einen Fehler abfangen müssen, wenn er geworfen wird, andernfalls wird der Prozess ausgeführt crash: In der asynchronen Version ist es dem Autor überlassen, ob wie gezeigt ein Fehler ausgegeben werden soll.

Erweitern wir unser Beispiel ein wenig:

const fs = require('fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read
console.log(data);
// moreWork(); will run after console.log

Hier ist ein ähnliches, aber nicht äquivalentes asynchrones Beispiel:

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
  console.log(data);
});
// moreWork(); will run before console.log

Im ersten Beispiel oben würden wir moreWork() heißen Vor console.log ist fs.readFile() im zweiten Beispiel nicht blockierend, sodass die JavaScript-Ausführung fortgesetzt werden kann und moreWork() zuerst aufgerufen wird und ist ein Schlüssel Designauswahl, die den Durchsatz verbessern kann. moreWork()

Parallelität und Durchsatz

Die JavaScript-Ausführung in Node.js ist Single-Threaded, daher bezieht sich Parallelität auf die Fähigkeit der Ereignisschleife, JavaScript-Rückruffunktionen auszuführen, nachdem andere Arbeiten abgeschlossen sind, jeder erwartete Code, der ausgeführt wird concurrently muss zulassen, dass die Ereignisschleife weiter ausgeführt wird, während Nicht-JavaScript-Vorgänge (z. B. E/A) stattfinden.

Betrachten wir als Beispiel eine Situation, in der die Ausführung jeder Webserver-Anfrage 50 ms dauert. Davon sind 45 ms Datenbank-E/A, die asynchron ausgeführt werden können 45 Millisekunden, um andere Anfragen zu bearbeiten, allein durch die Wahl einer nicht blockierenden Methode anstelle einer blockierenden Methode, was einen erheblichen Kapazitätsunterschied darstellt.

Ereignisschleifen unterscheiden sich vom Modell in vielen anderen Sprachen, bei denen zusätzliche Threads erstellt werden können, um gleichzeitige Arbeit zu erledigen.

Die Gefahren der Vermischung von blockierendem und nicht blockierendem Code

Es gibt einige Muster, die beim Umgang mit E/A vermieden werden sollten, schauen wir uns ein Beispiel an:

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
  console.log(data);
});
fs.unlinkSync('/file.md');
Im obigen Beispiel wird fs .unlinkSync() höchstwahrscheinlich vor fs.readFile() ausgeführt, wodurch file.md gelöscht wird, bevor es tatsächlich gelesen wird. Eine bessere Schreibmethode ist völlig nicht blockierend und garantiert korrekt ausgeführt Reihenfolge:

const fs = require('fs');
fs.readFile('/file.md', (readFileErr, data) => {
  if (readFileErr) throw readFileErr;
  console.log(data);
  fs.unlink('/file.md', (unlinkErr) => {
    if (unlinkErr) throw unlinkErr;
  });
});
Das Obige führt einen nicht blockierenden Aufruf von fs.unlink() im Rückruf von fs.readFile() durch, der die korrekte Reihenfolge der Operationen gewährleistet.

Das obige ist der detaillierte Inhalt vonEine Erklärung zum Blockieren und Nichtblockieren in Node.js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:https://segmentfault.com/a/1190000017016894. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen