web-dev-qa-db-fra.com

fs.readFileSync semble plus rapide que fs.readFile - puis-je l'utiliser pour une application Web en production?

Je sais que lors du développement en noeud, vous devriez toujours essayer d'éviter le blocage (synchronisation) des fonctions et aller avec les fonctions asynchrones, mais j'ai un petit test pour voir comment elles se comparent.

Je dois ouvrir un fichier JSON contenant des données i18n (telles que les formats de date et d'heure, etc.) et les transmettre à une classe qui utilise ces données pour formater des nombres, etc. dans mes vues.

Il serait assez délicat de commencer à envelopper toutes les méthodes de la classe dans des callbacks, aussi, si possible, j'utiliserais plutôt la version synchrone. 

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');

Cela se traduit par les lignes suivantes dans ma console:

two: 1ms
one: 159ms

Il semble que fs.readFileSync soit environ 150 fois plus rapide que fs.readFile et qu’il faut environ 1 ms pour charger un fichier json de 50 Ko (minifié). Tous mes fichiers JSON sont environ 50-100KB.

Je pensais aussi peut-être en quelque sorte mémoriser ou enregistrer ces données json en session afin que le fichier ne soit lu qu'une fois par session (ou lorsque l'utilisateur modifie ses paramètres régionaux). Je ne suis pas tout à fait sûr de savoir comment faire cela, c'est juste une idée.

Puis-je utiliser fs.readFileSync dans mon cas ou vais-je avoir des ennuis plus tard?

38
ragulka

Non, il n'est pas correct d'utiliser un appel d'API bloquant dans un serveur de noeud tel que vous le décrivez. La réactivité de votre site à de nombreuses connexions simultanées prendra un énorme succès. C'est aussi une violation flagrante du principe n ° 1 du nœud.

Le bon fonctionnement du nœud réside dans le fait qu’en attendant l’IO, il effectue simultanément un traitement CPU/mémoire. Cela nécessite exclusivement des appels asynchrones. Ainsi, si vous avez 100 clients lisant 100 fichiers JSON, node peut demander au système d'exploitation de lire ces 100 fichiers, mais en attendant que le système d'exploitation renvoie les données du fichier quand elles sont disponibles, le nœud peut traiter d'autres aspects de ces 100 demandes de réseau. Si vous avez un seul appel synchrone, le traitement de TOUS vos clients s’arrête complètement pendant la fin de cette opération. Ainsi, la connexion du client numéro 100 attend sans aucun traitement pendant la lecture séquentielle des fichiers du client 1, 2, 3, 4, etc. C'est Failville.

Voici une autre analogie. Si vous alliez au restaurant et étiez le seul client, vous obtiendrez probablement un service plus rapide si une seule personne vous attendait, prend votre commande, la fait cuire, vous la sert et gère la facture sans les frais généraux de coordination liés au traitement hôte/hôte. hôtesse, serveur, chef cuisinier, cuisiniers à la chaîne, caissiers, etc. Cependant, avec 100 clients dans le restaurant, la coordination supplémentaire signifie que les choses se passent en parallèle et la réactivité globale du restaurant est bien supérieure à ce qu'elle serait si une seule personne essayer de gérer 100 clients par leurs propres moyens.

63
Peter Lyons

Vous bloquez le rappel de la lecture asynchrone avec votre lecture synchrone, rappelez-vous single thread . Maintenant, je comprends que le décalage horaire est toujours incroyable, mais vous devriez essayer avec un fichier beaucoup, beaucoup plus long à lire et imaginer que beaucoup, beaucoup de clients feront de même, alors seulement les frais généraux seront rentables Cela devrait répondre à votre question, oui, vous rencontrerez des difficultés si vous répondez à des milliers de demandes avec blocage des entrées-sorties.

10
lab419

Après beaucoup de temps et beaucoup d'apprentissage et de pratique, j'ai essayé une fois de plus et j'ai trouvé la réponse et je peux montrer quelques exemples:

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