Mam CSV
plik 35 GB . Chcę przeczytać każdą linię i napisać linię do nowego pliku CSV, jeśli pasuje do określonego warunku.
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");
});
}
}
To zajmuje około 7 minut. Czy można jeszcze bardziej przyspieszyć ten proces?
java
java-stream
java-io
Membersound
źródło
źródło
parallel
go przyspieszy? I czy to nie przesuwa linii wokół?BufferedWriter
siebie, używając konstruktora, który pozwala ustawić rozmiar bufora. Być może większy (lub mniejszy) rozmiar bufora zrobi różnicę. Spróbowałbym dopasowaćBufferedWriter
rozmiar bufora do rozmiaru bufora systemu operacyjnego hosta.Odpowiedzi:
Jeśli jest to opcja, można użyć GZipInputStream / GZipOutputStream, aby zminimalizować dyskowe operacje we / wy.
Pliki.newBufferedReader / Writer używają domyślnego rozmiaru bufora, jak sądzę. Możesz wypróbować większy bufor.
Konwersja na ciąg, Unicode, spowalnia do (i zużywa dwukrotnie pamięć). Zastosowany UTF-8 nie jest tak prosty jak StandardCharsets.ISO_8859_1.
Najlepiej byłoby, gdybyś przeważnie pracował z bajtami i tylko dla określonych pól CSV przekonwertował je na String.
Plik odwzorowany w pamięci może być najbardziej odpowiedni. Zakresy plików mogą być używane równolegle, plując plik.
Stanie się to trochę dużym kodem, wprowadzanie wierszy od razu
(byte)'\n'
, ale nie będzie zbyt skomplikowane.źródło
GZipInputStream + GZipOutputStream
pełną pamięć na ramdysku. Wydajność była znacznie gorsza ...MappedByteBuffer
z ostatniej znanej dobrej pozycji (FileChannel.map
trwa długo).new RandomAccessFile(…).getChannel()
. Po prostu użyjFileChannel.open(…)
.możesz spróbować:
Myślę, że pozwoli ci to zaoszczędzić jedną lub dwie minuty. test można wykonać na moim komputerze w ciągu około 4 minut, określając rozmiar bufora.
czy może być szybciej? Spróbuj tego:
Powinno to zaoszczędzić trzy lub cztery minuty.
Jeśli to wciąż za mało. (Myślę, że prawdopodobnie zadajesz pytanie, dlatego musisz wielokrotnie wykonywać to zadanie). jeśli chcesz to zrobić w ciągu jednej minuty lub nawet kilku sekund. następnie powinieneś przetworzyć dane i zapisać je w db, a następnie przetworzyć zadanie przez wiele serwerów.
źródło
cbuf
zawartość i wypisać tylko fragmenty? I czy musiałbym zresetować bufor po zapełnieniu? (skąd mam wiedzieć, że bufor jest pełny?)Dzięki wszystkim twoim sugestiom najszybciej wymyśliłem wymianę pisarza
BufferedOutputStream
, co dało poprawę o około 25%:Nadal
BufferedReader
działa lepiej niżBufferedInputStream
w moim przypadku.źródło