web-dev-qa-db-fra.com

Comment résoudre l’erreur de mémoire dans Python

J'ai affaire à plusieurs gros fichiers txt, chacun d'eux a environ 8000000 lignes. Voici un court exemple des lignes:

usedfor zipper fasten_coat
usedfor zipper fasten_jacket
usedfor zipper fasten_pant
usedfor your_foot walk
atlocation camera cupboard
atlocation camera drawer
atlocation camera house
relatedto more plenty

Le code pour les stocker dans un dictionnaire est:

dicCSK = collections.defaultdict(list)
for line in finCSK:
    line=line.strip('\n')
    try:
        r, c1, c2 = line.split(" ")
    except ValueError:
        print line
    dicCSK[c1].append(r+" "+c2)

Il fonctionne bien dans le premier fichier txt, mais lorsqu’il s’exécute dans le deuxième fichier txt, j’ai reçu une erreur MemoryError.

J'utilise Windows 7 64 bits avec python 2,7 32 bits, processeur Intel i5, avec 8 Go de mémoire. Comment puis-je résoudre le problème?

Explication supplémentaire: J'ai quatre gros fichiers, chaque fichier contenant des informations différentes pour de nombreuses entités. Par exemple, je souhaite rechercher toutes les informations relatives à cat, à son nœud père animal et à son nœud enfant persian cat etc. Donc, mon programme a d'abord lu tous les fichiers txt du dictionnaire, puis j'ai parcouru tous les dictionnaires pour trouver des informations sur cat, son père et ses enfants.

10
flyingmouse

La solution la plus simple: vous êtes probablement à court d'espace d'adressage virtuel (toute autre forme d'erreur signifie généralement que vous courez très lentement pendant une longue période avant d'obtenir finalement un MemoryError). En effet, une application 32 bits sous Windows (et la plupart des systèmes d’exploitation) est limitée à 2 Go d’espace adresse en mode utilisateur (Windows peut être modifié pour en faire 3 Go, mais la limite est tout de même réduite). Vous avez 8 Go de RAM, mais votre programme ne peut pas en utiliser (au moins) 3/4. Python génère pas mal de temps système par en-tête (en-tête d’objet, alignement d’allocation, etc.), les chaînes sont probablement utilisées par près de 1 Go de mémoire vive, et ce avant de traiter les frais généraux du dictionnaire, le reste de votre programme, le reste de Python, etc. Si l'espace mémoire est suffisamment fragmenté et que le dictionnaire doit croître, il risque de ne pas disposer de suffisamment d'espace contigu pour être réaffecté et vous obtiendrez un MemoryError.

Installez une version 64 bits de Python (si vous le pouvez, je vous recommanderais de passer à Python 3 pour d'autres raisons)); il utilisera plus de mémoire, mais alors, il aura accès à un lot plus d'espace mémoire (et plus physique RAM aussi)).

Si cela ne suffit pas, envisagez de convertir en un sqlite3 base de données (ou une autre base de données), de sorte qu'elle se déverse naturellement sur le disque lorsque les données deviennent trop volumineuses pour la mémoire principale, tout en permettant une recherche assez efficace.

20
ShadowRanger

En supposant que votre exemple de texte soit représentatif de tout le texte, une ligne consomme environ 75 octets sur ma machine:

In [3]: sys.getsizeof('usedfor zipper fasten_coat')
Out[3]: 75

Faire des calculs approximatifs:

75 bytes * 8,000,000 lines / 1024 / 1024 = ~572 MB

Il faut donc environ 572 Mo pour stocker les chaînes seules pour l’un de ces fichiers. Une fois que vous commencez à ajouter des fichiers supplémentaires, structurés et dimensionnés de la même manière, vous vous approchez rapidement des limites de votre espace d'adressage virtuel, comme indiqué dans la réponse de @ ShadowRanger.

Si mettre à niveau votre python n'est pas faisable pour vous, ou s'il ne fait que lancer la boîte (vous avez une mémoire physique finie après tout), vous avez vraiment deux options: écrivez vos résultats dans des fichiers temporaires entre le chargement et la lecture des fichiers d'entrée, ou l'écriture de vos résultats dans une base de données. Comme vous devez post-traiter davantage les chaînes après les avoir agrégées, l'écriture dans une base de données serait la meilleure approche.

5
Levi Noecker