J'ai un CSV
fichier de 35 Go . Je veux lire chaque ligne et écrire la ligne dans un nouveau CSV s'il correspond à une condition.
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");
});
}
}
Cela prend env. 7 minutes. Est-il possible d'accélérer encore plus ce processus?
java
java-stream
java-io
membersound
la source
la source
parallel
rend plus rapide? Et cela ne change-t-il pas les lignes?BufferedWriter
vous - même, en utilisant le constructeur qui vous permet de définir la taille du tampon. Peut-être qu'une taille de tampon plus grande (ou plus petite) fera une différence. J'essaierais de faire correspondre laBufferedWriter
taille de la mémoire tampon à la taille de la mémoire tampon du système d'exploitation hôte.Réponses:
S'il s'agit d'une option, vous pouvez utiliser GZipInputStream / GZipOutputStream pour minimiser les E / S de disque.
Files.newBufferedReader / Writer utilise une taille de tampon par défaut, 8 Ko je crois. Vous pouvez essayer un tampon plus grand.
La conversion en chaîne, Unicode, ralentit (et utilise deux fois la mémoire). L'UTF-8 utilisé n'est pas aussi simple que StandardCharsets.ISO_8859_1.
Le mieux serait si vous pouvez travailler avec des octets pour la plupart et uniquement pour des champs CSV spécifiques les convertir en chaîne.
Un fichier mappé en mémoire peut être le plus approprié. Le parallélisme peut être utilisé par des plages de fichiers, crachant le fichier.
Cela deviendra un peu beaucoup de code, pour obtenir des lignes droites
(byte)'\n'
, mais pas trop complexes.la source
GZipInputStream + GZipOutputStream
totalement inmemory sur un ramdisk. La performance était bien pire ...MappedByteBuffer
partir de la dernière position connue (FileChannel.map
prend longtemps).new RandomAccessFile(…).getChannel()
. Utilisez simplementFileChannel.open(…)
.vous pouvez essayer ceci:
Je pense que cela vous fera gagner une ou deux minutes. le test peut être effectué sur ma machine en environ 4 minutes en spécifiant la taille du tampon.
cela pourrait-il être plus rapide? essaye ça:
Cela devrait vous faire économiser trois ou quatre minutes.
Si cela ne suffit toujours pas. (La raison pour laquelle je suppose que vous posez la question est probablement que vous devez exécuter la tâche à plusieurs reprises). si vous voulez le faire en une minute ou même quelques secondes. vous devez alors traiter les données et les enregistrer dans db, puis traiter la tâche par plusieurs serveurs.
la source
cbuf
contenu et écrire uniquement des portions? Et devrais-je réinitialiser le tampon une fois plein? (Comment puis-je savoir que le tampon est plein?)Grâce à toutes vos suggestions, le plus rapide que j'ai trouvé a été d'échanger avec l'écrivain
BufferedOutputStream
, ce qui a donné une amélioration d'environ 25%:Pourtant, les
BufferedReader
performances sont meilleures queBufferedInputStream
dans mon cas.la source