Alguien vuelve a estar equivocado en Internet: en el Nodo semanal de ayer había un enlace a una publicación en la que el autor intentaba medir y comparar el rendimiento de Stream API en Node.js. La tristeza causa cómo el autor trabaja con las transmisiones y qué conclusiones trata de sacar en base a esto:
... esto funcionó bastante bien en archivos más pequeños, pero una vez que llegué al archivo más grande, ocurrió el mismo error. Aunque Node.js estaba transmitiendo las entradas y salidas, todavía intentó mantener todo el archivo en la memoria mientras realizaba las operaciones.
Tratemos de descubrir qué está mal con las conclusiones y el código del autor.
Desde mi punto de vista, el problema es que el autor del artículo no sabe cómo usar Stream'ami y este es un problema que uno tiene que resolver con bastante frecuencia. Este fenómeno, en mi opinión, tiene tres razones:
- La compleja historia de Node.js Stream API: el dolor y el sufrimiento descritos aquí
- No es la API más intuitiva si intentas usarla sin envoltorios
- Documentación bastante extraña que presenta las transmisiones como algo muy complejo y de bajo nivel.
En conjunto, esto lleva al hecho de que los desarrolladores a menudo no saben cómo y no quieren usar la API Stream.
¿Qué tiene de malo el código de autor ?
Para comenzar, repitamos la tarea aquí (el original en inglés y un enlace al archivo se pueden encontrar en la publicación):
Hay un cierto archivo de 2.5 GB con líneas de la forma:
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
Debe analizarlo y encontrar la siguiente información:
- El número de líneas en el archivo.
- Nombres en las líneas 432 y 43243 (aquí la verdad surge la cuestión de cómo contar, ¿de 0 o 1?)
- El nombre más común y cuántas veces ocurre
- La cantidad de cuotas por mes
Cual es el problema - El autor dice honestamente que carga todo el archivo en la memoria y debido a esto, el Nodo se "cuelga" y el autor nos da un hecho interesante.
Dato curioso: Node.js solo puede almacenar hasta 1,67 GB de memoria al mismo tiempo
El autor hace una extraña conclusión a partir de este hecho de que son Streams los que cargan todo el archivo en la memoria, y no escribió el código incorrecto.
Vamos a refutar la tesis: " Aunque Node.js estaba transmitiendo las entradas y salidas, todavía se intenta mantener todo el archivo ", escribiendo un pequeño programa que contará el número de líneas en un archivo de cualquier tamaño:
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 : el código se escribe intencionalmente de la manera más simple posible. ¡Las variables globales son malas!
A qué debe prestar atención:
- split - npm un paquete que recibe una secuencia de líneas en la "entrada" - devuelve una secuencia de conjuntos de líneas a la "salida" con un salto de línea separado. Lo más probable es que se realice como una implementación del flujo de transformación. Conectamos nuestro ReadStream con un archivo y lo conectamos a ...
- linecounter - Implementación de WritableStream. En él, implementamos dos métodos: para procesar una pieza (fragmento) y varios. La "línea" en esta situación es la línea de código. Reverso: agregue el número deseado al contador. Es importante comprender que en esta situación no cargaremos todo el archivo en la memoria, y la API dividirá todo para nosotros en "piezas" que sean más convenientes para el procesamiento
- 'terminar': eventos que "suceden" cuando los datos que llegan a nuestro ReadableStream "finalizan". Cuando esto sucede, nos comprometemos a contrarrestar los datos.
Bueno, probemos nuestra creación en un archivo grande:
> node linecounter.js 13903993
Como puedes ver, todo funciona. De lo que podemos concluir que Stream API hace un excelente trabajo con archivos de cualquier tamaño y la declaración del autor de la publicación, por decirlo suavemente, no es cierta. Aproximadamente de la misma manera, podemos calcular cualquier otro valor requerido en el problema.
Decir:
- ¿Está interesado en leer cómo resolver el problema por completo y cómo llevar el código resultante a una forma conveniente para el mantenimiento?
- ¿Utiliza Stream API y qué dificultades encontró?