Python >> Tutoriel Python >  >> Python

Lecture efficace d'un fichier XML de 800 Go en Python 2.7

La norme open() fonction déjà, par défaut, renvoie un fichier tamponné (si disponible sur votre plate-forme). Pour les objets de fichier qui sont habituellement entièrement tamponné.

Généralement signifie ici que Python laisse cela à l'implémentation C stdlib ; il utilise un fopen() appeler (wfopen() sous Windows pour prendre en charge les noms de fichiers UTF-16), ce qui signifie que la mise en mémoire tampon par défaut pour un fichier est choisie ; sous Linux, je crois que ce serait 8kb. Pour une opération de lecture pure comme l'analyse XML, ce type de mise en mémoire tampon est exactement ce que vous voulez.

L'analyse XML effectuée par iterparse lit le fichier par tranches de 16384 octets (16 Ko).

Si vous voulez contrôler la taille du tampon, utilisez le buffering argument de mot-clé :

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

qui remplacera la taille de tampon par défaut (qui, je m'attendrais à ce qu'elle corresponde à la taille du bloc de fichier ou à un multiple de celle-ci). Selon cet article, augmenter le tampon de lecture devrait help, et l'utilisation d'une taille d'au moins 4 fois la taille de bloc de lecture attendue plus 8 octets va améliorer les performances de lecture. Dans l'exemple ci-dessus, je l'ai défini sur 8 fois la taille de lecture d'ElementTree.

Le io.open() La fonction représente la nouvelle structure d'objets d'E/S Python 3, où les E/S ont été divisées en une nouvelle hiérarchie de types de classes pour vous donner plus de flexibilité. Le prix est plus indirect, plus de couches pour que les données doivent traverser, et le code Python C fait plus de travail lui-même au lieu de laisser cela au système d'exploitation.

Vous pourriez essayez de voir si io.open('foo.xml', 'rb', buffering=2<<16) va faire mieux. Ouverture en rb mode vous donnera un io.BufferedReader exemple.

Vous ne faites pas voulez utiliser io.TextIOWrapper; l'analyseur d'expat sous-jacent veut des données brutes car il décodera votre fichier XML en s'encodant lui-même. Cela ne ferait qu'ajouter des frais généraux supplémentaires; vous obtenez ce type si vous ouvrez en r (mode texte) à la place.

Utilisation du io.open() peut vous donner plus de flexibilité et une API plus riche, mais l'objet de fichier C sous-jacent est ouvert à l'aide de open() au lieu de fopen() , et toute la mise en mémoire tampon est gérée par le Python io.BufferedIOBase mise en œuvre.

Votre problème sera le traitement de cette bête, pas le fichier lu, je pense. De toute façon, le cache du disque sera quasiment épuisé lors de la lecture d'un fichier de 800 Go.