Quelqu'un a encore tort sur Internet - dans Yesterday Node Weekly, il y avait un lien vers une publication dans laquelle l'auteur essayait de mesurer et de comparer les performances de l'API Stream dans Node.js. La tristesse explique comment l'auteur travaille avec les flux et quelles conclusions il essaie de tirer sur cette base:
... cela a plutôt bien fonctionné sur des fichiers plus petits, mais une fois arrivé au plus gros fichier, la même erreur s'est produite. Bien que Node.js diffuse les entrées et les sorties, il a tout de même tenté de conserver l'ensemble du fichier en mémoire lors de l'exécution des opérations.
Essayons de comprendre ce qui ne va pas avec les conclusions et le code de l'auteur.
De mon point de vue, le problème est que l'auteur de l'article ne sait pas utiliser Stream'ami et c'est un problème que l'on doit traiter assez souvent. Ce phénomène, à mon avis, a trois raisons:
- L'histoire complexe de l'API Node.js Stream - la douleur et la souffrance décrites ici
- Pas l'API la plus intuitive si vous essayez de l'utiliser sans wrappers
- Documentation assez étrange qui présente les flux comme quelque chose de très complexe et de bas niveau
Dans l'ensemble, cela conduit au fait que les développeurs ne savent souvent pas comment et ne veulent pas utiliser l'API Stream.
Quel est le problème avec le code d'auteur ?
Pour commencer, répétons la tâche ici (l'original en anglais et un lien vers le fichier se trouvent dans le post):
Il existe un certain fichier de 2,5 Go avec des lignes du formulaire:
C00084871|N|M3|P|201703099050762757|15|IND|COLLINS, DARREN ROBERT|SOUTHLAKE|TX|760928782|CELANESE|VPCHOP&TECH|02282017|153||PR2552193345215|1151824||P/R DEDUCTION ($76.92 BI-WEEKLY)|4030920171380058715
Vous devez l'analyser et trouver les informations suivantes:
- Le nombre de lignes dans le fichier
- Noms sur les 432e et 43243e lignes (ici la vérité se pose la question de savoir comment compter, à partir de 0 ou 1?)
- Le nom le plus courant et le nombre de fois qu'il apparaît
- Le nombre de versements pour chaque mois
Quel est le problème? - L'auteur dit honnêtement qu'il charge l'intégralité du fichier en mémoire et à cause de cela, Node "se bloque" et l'auteur nous donne un fait intéressant.
Fait amusant: Node.js ne peut contenir jusqu'à 1,67 Go de mémoire à la fois
L'auteur tire une conclusion étrange de ce fait que ce sont les Streams qui chargent tout le fichier en mémoire et qu'il n'a pas écrit le mauvais code.
Réfutons la thèse: " Bien que Node.js diffuse les entrées et les sorties, il est toujours tenté de conserver l'intégralité du fichier ", en écrivant un petit programme qui comptera le nombre de lignes dans un fichier de n'importe quelle taille:
const { Writable } = require('stream') const fs = require('fs') const split = require('split') let counter = 0 const linecounter = new Writable({ write(chunk, encoding, callback) { counter = counter + 1 callback() }, writev(chunks, callback) { counter = counter + chunks.length callback() } }) fs.createReadStream('itcont.txt') .pipe(split()) .pipe(linecounter) linecounter.on('finish', function() { console.log(counter) })
NB : le code est volontairement écrit le plus simplement possible. Les variables globales sont mauvaises!
À quoi devez-vous faire attention:
- split - npm un paquet qui reçoit un flux de lignes à l '"entrée" - renvoie un flux d'ensembles de lignes à la "sortie" avec un saut de ligne séparé. Très probablement réalisé comme une implémentation du flux de transformation. Nous y canalisons notre ReadStream avec un fichier, et nous nous canalisons dans ...
- linecounter - Implémentation de WritableStream. Dans ce document, nous implémentons deux méthodes: pour traiter une seule pièce (morceau) et plusieurs. La «ligne» dans cette situation est la ligne de code. Inverser - ajoutez le nombre souhaité au compteur. Il est important de comprendre que dans cette situation, nous ne chargerons pas l'intégralité du fichier en mémoire, et l'API divisera tout pour nous en «morceaux» les plus pratiques pour le traitement
- «terminer» - événements qui «se produisent» lorsque les données arrivant à notre ReadableStream «se terminent». Lorsque cela se produit, nous promettons des données de compteur
Eh bien, testons notre création sur un gros fichier:
> node linecounter.js 13903993
Comme vous pouvez le voir, tout fonctionne. D'après ce que nous pouvons conclure que l'API Stream fait un excellent travail avec des fichiers de toute taille et la déclaration de l'auteur de l'article, pour le moins, n'est pas vraie. De la même manière, nous pouvons calculer toute autre valeur requise dans le problème.
Dites:
- Êtes-vous intéressé à lire comment résoudre complètement le problème et comment mettre le code résultant sous une forme pratique pour la maintenance?
- Utilisez-vous Stream API et quelles difficultés avez-vous rencontrées?