Wydajny odczyt pliku XML 800 GB w Pythonie 2.7

Czytam plik xml 800 GB w Pythonie 2.7 i analizuję go za pomocą iteracyjnego parsera etree.

Obecnie używam tylko open('foo.txt') bez argumentu buforującego. Jestem trochę zdezorientowany, czy to jest podejście, które powinienem przyjąć, czy powinienem użyć argumentu buforującego lub użyć czegoś z io, takiego jak io.BufferedReader lub io.open lub io.TextIOBase.

Punkt we właściwym kierunku byłby bardzo mile widziany.
Author: Martijn Pieters, 2013-02-14

3 answers

Standard open() function już domyślnie zwraca buforowany plik (jeśli jest dostępny na twojej platformie). Dla obiektów plików, które są zazwyczaj w pełni buforowane.

zazwyczaj tutaj oznacza, że Python pozostawia to implementacji C stdlib; używa fopen() call (wfopen() W Windows do obsługi nazw plików UTF-16), co oznacza, że domyślne buforowanie pliku jest wybierane; w Linuksie sądzę, że byłoby to 8kB. Do operacji czysto odczytywanych, takich jak Analizowanie XML tego typu buforowanie jest dokładnie tym, czego chcesz.

Analiza XML wykonana przez iterparse odczytuje plik w kawałkach po 16384 bajtów (16kb).

Jeśli chcesz kontrolować buffersize, użyj argumentu słowa kluczowego buffering:

open('foo.xml', buffering=(2<<16) + 8)  # buffer enough for 8 full parser reads

, który nadpisze domyślny rozmiar bufora(którego spodziewałbym się dopasować do rozmiaru bloku pliku lub jego wielokrotności). Zgodnie z ten artykuł zwiększenie bufora odczytu powinno pomóc, a użycie rozmiaru co najmniej 4 razy oczekiwany rozmiar bloku odczytu plus 8 bajtów poprawi wydajność odczytu. W powyższym przykładzie ustawiłem go na 8 razy Rozmiar odczytu ElementTree.

The io.open() function reprezentuje nową strukturę obiektów we/wy Pythona 3, gdzie we / wy zostały podzielone na nową hierarchię typów klas, aby zapewnić Ci większą elastyczność. Cena jest bardziej indirection, więcej warstw dla danych, aby przejść przez, a kod Python C robi więcej pracy sam zamiast zostawić to do OS.

Ty mógłbyś spróbować i sprawdzić, czy io.open('foo.xml', 'rb', buffering=2<<16) będzie lepiej. Otwarcie w trybie rb da ci io.BufferedReader instancja .

Robisz a nie chcesz używać io.TextIOWrapper; bazowy Parser expat chce surowych danych, ponieważ sam dekoduje kodowanie pliku XML. To tylko dodać dodatkowe koszty; otrzymasz ten typ, jeśli otworzysz w r (textmode) zamiast.

Korzystanie z io.open() może dać ci większą elastyczność i bogatsze API, ale bazowy obiekt pliku C jest otwierany za pomocą open() zamiast fopen(), a całe buforowanie jest obsługiwane przez implementację Pythona io.BufferedIOBase.

Twoim problemem będzie przetwarzanie tej bestii, Nie plik czyta, myślę. Pamięć podręczna dysku i tak zostanie prawie zastrzelona podczas czytania pliku 800GB.

 14
Author: Martijn Pieters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-14 17:36:12

Próbowałeś leniwej funkcji?: leniwa Metoda odczytu dużego pliku w Pythonie?

To chyba już odpowiada na twoje pytanie. Jednak rozważyłbym użycie tej metody do zapisu danych do bazy danych, mysql jest darmowy: http://dev.mysql.com/downloads / , NoSQL jest również darmowy i może być nieco bardziej dostosowany do operacji obejmujących zapis 800gb danych lub podobnych ilości: http://www.oracle.com/technetwork/database/nosqldb/downloads/default-495311.html

 1
Author: RandomUs1r,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:11

Nie próbowałem tego z tak epickimi plikami xml, ale ostatnio miałem do czynienia z dużymi (i stosunkowo prostymi) plikami xml, użyłem parsera sax .

To w zasadzie daje wywołania zwrotne dla każdego "zdarzenia" i pozostawia to do przechowywania danych, których potrzebujesz. Możesz dać otwarty plik, więc nie musisz go czytać w całości na raz.

 1
Author: JCash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-13 23:10:28