Tengo un CSV
archivo de 35 GB . Quiero leer cada línea y escribir la línea en un nuevo CSV si coincide con una condición.
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get("source.csv"))) {
try (BufferedReader br = Files.newBufferedReader(Paths.get("target.csv"))) {
br.lines().parallel()
.filter(line -> StringUtils.isNotBlank(line)) //bit more complex in real world
.forEach(line -> {
writer.write(line + "\n");
});
}
}
Esto toma aprox. 7 minutos ¿Es posible acelerar ese proceso aún más?
java
java-stream
java-io
miembros
fuente
fuente
parallel
hace más rápido? ¿Y eso no mezcla las líneas?BufferedWriter
usted mismo, utilizando el constructor que le permite establecer el tamaño del búfer. Tal vez un tamaño de búfer más grande (o más pequeño) hará la diferencia. Intentaría hacer coincidir elBufferedWriter
tamaño del búfer con el tamaño del búfer del sistema operativo del host.Respuestas:
Si es una opción, puede usar GZipInputStream / GZipOutputStream para minimizar la E / S de disco.
Files.newBufferedReader / Writer utiliza un tamaño de búfer predeterminado, 8 KB, creo. Puede probar un búfer más grande.
Al convertir a String, Unicode, se ralentiza (y usa el doble de memoria). El UTF-8 usado no es tan simple como StandardCharsets.ISO_8859_1.
Lo mejor sería si puede trabajar con bytes en su mayor parte y solo para campos CSV específicos convertirlos a String.
Un archivo mapeado en memoria podría ser el más apropiado. Paralelismo puede ser utilizado por rangos de archivos, escupiendo el archivo.
Esto se convertirá en un poco de código, haciendo que las líneas funcionen correctamente
(byte)'\n'
, pero no demasiado complejas.fuente
GZipInputStream + GZipOutputStream
completamente la memoria en un disco RAM. El rendimiento fue mucho peor ...MappedByteBuffer
desde la última posición buena conocida (FileChannel.map
toma mucho tiempo).new RandomAccessFile(…).getChannel()
. Solo úsaloFileChannel.open(…)
.puedes probar esto:
Creo que te ahorrará uno o dos minutos. La prueba se puede hacer en mi máquina en aproximadamente 4 minutos especificando el tamaño del búfer.
¿podría ser más rápido? prueba esto:
Esto debería ahorrarte tres o cuatro minutos.
Si eso todavía no es suficiente. (La razón por la que supongo que hace la pregunta probablemente es que necesita ejecutar la tarea repetidamente). si quieres hacerlo en un minuto o incluso un par de segundos. entonces debe procesar los datos y guardarlos en db, luego procesar la tarea por varios servidores.
fuente
cbuf
contenido y solo escribir porciones? ¿Y tendría que restablecer el búfer una vez lleno? (¿cómo puedo saber que el búfer está lleno?)Gracias a todas sus sugerencias, lo más rápido que se me ocurrió fue intercambiar el escritor
BufferedOutputStream
, lo que dio una mejora aproximada del 25%:Aún así
BufferedReader
funciona mejor queBufferedInputStream
en mi caso.fuente