it-swarm.com.de

fs.readFileSync scheint schneller zu sein als fs.readFile - ist die Verwendung für eine Web-App in der Produktion in Ordnung?

Ich weiß, dass Sie beim Entwickeln in Knoten immer versuchen sollten, blockierende (Synchronisierungs-) Funktionen zu vermeiden und async-Funktionen zu verwenden. Allerdings habe ich ein wenig getestet, um zu sehen, wie sie miteinander verglichen werden.

Ich muss eine Json-Datei öffnen, die I18n-Daten (wie Datums- und Zeitformate usw.) enthält, und diese Daten an eine Klasse übergeben, die diese Daten zum Formatieren von Zahlen usw. in meinen Ansichten verwendet.

Es wäre ziemlich umständlich, alle Methoden der Klasse in Callbacks einzubinden. Wenn möglich, würde ich stattdessen die synchrone Version verwenden. 

console.time('one');
console.time('two');
fs.readFile( this.dir + "/" + locale + ".json", function (err, data) {
  if (err) cb( err );
  console.timeEnd('one');
});
var data = fs.readFileSync( this.dir + "/" + locale + ".json" );
console.timeEnd('two');

Daraus ergeben sich folgende Zeilen in meiner Konsole:

two: 1ms
one: 159ms

Es scheint, dass fs.readFileSync etwa 150-mal schneller als fs.readFile ist und etwa 1 ms benötigt, um eine 50-KB-Json-Datei zu laden (minified). Alle meine Json-Dateien haben etwa 50-100 KB.

Ich habe auch daran gedacht, diese Json-Daten irgendwie in einer Sitzung zu speichern oder zu speichern, sodass die Datei nur einmal pro Sitzung gelesen wird (oder wenn der Benutzer das Gebietsschema ändert). Ich bin mir nicht ganz sicher, wie das geht, es ist nur eine Idee.

Ist es in Ordnung, fs.readFileSync in meinem Fall zu verwenden, oder werde ich später in Schwierigkeiten geraten?

38
ragulka

Nein, es ist nicht in Ordnung, einen blockierenden API-Aufruf in einem Knotenserver zu verwenden. Die Reaktionszeit Ihrer Website auf viele gleichzeitige Verbindungen ist ein großer Erfolg. Es verstößt auch einfach gegen das Prinzip # 1 des Knotens.

Der Schlüssel zum Knoten ist, dass er auf IO wartet und gleichzeitig CPU/Speicher verarbeitet. Dies erfordert ausschließlich asynchrone Aufrufe. Wenn Sie also über 100 Clients verfügen, die 100 JSON-Dateien lesen, kann der Knoten das Betriebssystem zum Lesen dieser 100 Dateien auffordern. Wenn Sie jedoch darauf warten, dass das Betriebssystem die Dateidaten zurückgibt, wenn sie verfügbar sind, kann der Knoten andere Aspekte dieser 100 Netzwerkanforderungen verarbeiten. Wenn Sie dort einen einzigen synchronen Aufruf haben, wird ALLE Clientverarbeitung vollständig abgebrochen, während der Vorgang abgeschlossen ist. Daher wartet die Verbindung von Client Nummer 100 ohne Verarbeitung, während Sie Dateien für Client 1, 2, 3, 4 usw. nacheinander lesen. Das ist Failville.

Hier ist eine weitere Analogie. Wenn Sie in ein Restaurant gingen und der einzige Kunde wären, würden Sie wahrscheinlich einen schnelleren Service erhalten, wenn Sie von einer einzelnen Person gesessen, Ihre Bestellung angenommen, gekocht, Ihnen zugestellt und die Rechnung ohne den Koordinationsaufwand für den Umgang mit dem Gastgeber/Gastgeber erledigt wird. Hostess, Server, Küchenchef, Linienköche, Kassierer usw. Bei 100 Kunden im Restaurant bedeutet die zusätzliche Koordination jedoch, dass die Dinge parallel laufen, und die Reaktionsfähigkeit des Restaurants ist weit über das hinaus, was eine Einzelperson wäre versuchen, 100 Kunden alleine zu behandeln.

63
Peter Lyons

Sie blockieren den Rückruf des asynchronen Lesevorgangs mit Ihrem synchronen Lesevorgang - erinnern Sie sich an single thread . Nun verstehe ich, dass der Zeitunterschied immer noch erstaunlich ist, aber Sie sollten es mit einer Datei versuchen, die viel, viel länger zu lesen ist, und sich vorstellen, dass viele, viele Clients dasselbe tun werden, nur dann zahlt sich der Aufwand aus Damit sollte Ihre Frage beantwortet werden. Ja, Sie werden in Schwierigkeiten geraten, wenn Sie Tausende von Anfragen mit blockierender E/A bedienen.

10
lab419

Nach langer Zeit und viel Lernen und Üben habe ich es noch einmal versucht und ich habe die Antwort gefunden und kann ein Beispiel zeigen:

const fs = require('fs');

const syncTest = () => {
    let startTime = +new Date();
    const results = [];
    const files = [];

    for (let i=0, len=4; i<len; i++) {
        files.Push(fs.readFileSync(`file-${i}.txt`));
    };

    for (let i=0, len=360; i<len; i++) results.Push(Math.sin(i), Math.cos(i));
    console.log(`Sync version: ${+new Date() - startTime}`);
};

const asyncTest = () => {
    let startTime = +new Date();
    const results = [];
    const files = [];

    for (let i=0, len=4; i<len; i++) {
        fs.readFile(`file-${i}.txt`, file => files.Push(file));
    };

    for (let i=0, len=360; i<len; i++) results.Push(Math.sin(i), Math.cos(i));

    console.log(`Async version: ${+new Date() - startTime}`);
};

syncTest();
asyncTest();
0
buuuudzik

Ja, es ist richtig, mit der asynchronen Methode in einer serverseitigen Umgebung umzugehen. Wenn sich ihr Anwendungsfall jedoch von der Generierung des Builds wie im clientseitigen JS-Projekt unterscheidet, lesen und schreiben Sie die JSON-Dateien in der Zwischenzeit für verschiedene Varianten.

Es betrifft nicht so viel. Wir brauchten zwar eine schnelle Methode, um einen minimierten Build für die Bereitstellung zu erstellen (hier kommt Synchronous ins Spiel). für mehr Info und Bibliothek

0
Anupam Maurya