47 votes

Pourquoi mmap de Python ne fonctionne-t-il pas avec des fichiers volumineux?

Je suis en train d'écrire un module qui permet entre autre au niveau du bit d'accès en lecture aux fichiers. Les fichiers peuvent être grandes (des centaines de GO) j'ai donc écrit une classe simple qui me permet de traiter le fichier comme une chaîne et se cache l'ensemble de la recherche et de la lecture.

Au moment où j'ai écrit ma classe wrapper je ne connaissais pas le mmap module. À la lecture de la documentation pour mmap j'ai pensé "grand - c'est juste ce dont j'avais besoin, je vais prendre mon code et de le remplacer avec un mmap. C'est probablement beaucoup plus efficace et il est toujours bon de supprimer le code."

Le problème est que mmap ne fonctionne pas pour les gros fichiers! C'est très surprenant pour moi que je pensais que c'était peut-être l'application la plus évidente. Si le fichier est au-dessus de quelques gigaoctets puis-je obtenir un EnvironmentError: [Errno 12] Cannot allocate memory. Cela se produit uniquement avec un 32 bits Python construire de sorte qu'il semble qu'il est en cours d'exécution hors de l'espace d'adresse, mais je ne trouve pas de documentation sur ce sujet.

Mon code est juste

f = open('somelargefile', 'rb')
map = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)

Donc ma question est suis-je raté quelque chose d'évident ici? Est-il un moyen d'obtenir mmap à travailler de façon portable sur de gros fichiers, ou dois-je retourner à mon naïf fichier wrapper?


Mise à jour: Il semble y avoir un sentiment que le Python mmap devraient avoir les mêmes restrictions que la POSIX mmap. Pour mieux exprimer ma frustration ici est une simple classe qui a une petite partie de la fonctionnalité de mmap.

import os

class Mmap(object):
    def __init__(self, f):
        """Initialise with a file object."""
        self.source = f

    def __getitem__(self, key):
        try:
            # A slice
            self.source.seek(key.start, os.SEEK_SET)
            return self.source.read(key.stop - key.start)
        except AttributeError:
            # single element
            self.source.seek(key, os.SEEK_SET)
            return self.source.read(1)

Elle est en lecture seule et ne pas faire quelque chose de compliqué, mais je peux faire la même avec un mmap:

map2 = Mmap(f)
print map2[0:10]
print map2[10000000000:10000000010]

sauf qu'il n'y a pas de restrictions sur la taille des fichiers. Pas trop difficile, vraiment...

38voto

Nick Bastin Points 12627

IEEE 1003.1:

La fonction mmap() établit une correspondance entre d'adressage d'un processus l'espace ainsi qu'un fichier de la mémoire partagée objet, ou [TYM] tapé mémoire objet.

Elle a besoin de tout l'espace d'adressage virtuel parce que c'est exactement ce qu' mmap() n'.

Le fait qu'il n'est pas vraiment à cours de mémoire n'a pas d'importance, vous ne pouvez pas mapper plus d'espace d'adressage que vous avez disponible. Puisque vous prenez alors le résultat et l'accès comme si c' étaient de mémoire, comment exactement ce que vous propose l'accès à plus de 2^32 octets dans le fichier? Même si mmap() n'ont pas fait faillite, vous pourriez encore lu que le premier de 4 go avant de vous manqué de l'espace dans un espace d'adressage 32 bits. Vous pouvez, bien sûr, mmap() coulissante fenêtre de 32 bits sur le fichier, mais qui ne sont pas nécessairement net, vous avez tout avantage, à moins que vous pouvez optimiser votre modèle d'accès tels que vous limitez le nombre de fois que vous avez de la visite précédente de windows.

18voto

Scott Griffiths Points 8867

Désolé de répondre à ma propre question, mais je pense que le vrai problème que j'ai eu n'était pas de réaliser que mmap a été une norme POSIX système d'appel avec notamment characterisatations et limitations, et que le Python mmap est censé juste pour exposer son fonctionnement.

La documentation Python ne parle pas de l'POSIX mmap, et donc, si vous venez à elle en tant que programmeur Python sans beaucoup de connaissances de POSIX (comme je l'ai fait), puis l'adresse de l'espace problème semble tout à fait arbitraire et mal conçu!

Merci pour les autres affiches pour m'enseigner le vrai sens de la pamm. Malheureusement, personne n'a suggéré une meilleure alternative à mon fabriqués à la main en classe pour le traitement de gros fichiers comme des chaînes de caractères, donc je serai obligé de rester avec elle pour l'instant. Peut-être que je vais le nettoyer et de faire partie de mon module interface publique quand j'ai la chance.

17voto

Mark Ransom Points 132545

Un programme 32 bits et système d'exploitation ne s'adresse qu'à un maximum de 32 bits de mémoire c'est à dire de 4 go. Il y a d'autres facteurs qui font la totale, même les plus petites, par exemple, Windows se réserve entre 0,5 et 2 GO pour le matériel d'accès, et bien sûr, votre programme va prendre un certain espace.

Edit: la chose La plus évidente que vous êtes en manque, c'est une compréhension de la mécanique de mmap, sur n'importe quel système d'exploitation. Il permet de mapper une partie d'un fichier à une plage de mémoire - une fois que vous l'avez fait, tout accès à la partie du fichier qui se passe avec le moins possible de frais généraux. C'est une faible surcharge parce que le plan est fait une fois, et ne pas avoir à changer à chaque fois que vous accédez à une gamme différente. L'inconvénient est que vous avez besoin de l'adresse de gamme suffisante pour la partie que vous essayez de carte. Si vous êtes à la cartographie de l'ensemble du dossier à la fois, vous aurez besoin d'un trou dans la carte mémoire suffisamment grand pour contenir la totalité du fichier. Si ce trou n'existe pas, ou est plus grand que l'ensemble de votre espace d'adressage, il échoue.

9voto

IfLoop Points 59461

le mmap module fournit tous les outils dont vous avez besoin pour fouiner dans votre fichier de grande taille, mais en raison des limites d'autres personnes l'ont mentionné, vous ne pouvez pas mapper tout à la fois. Vous pouvez mapper un grand morceau à la fois, faire un peu de traitement, puis annuler le mappage et la carte de l'autre. les principaux arguments à l' mmap classe length et offset, qui font exactement ce qu'ils ressemblent, vous permettant de mapper length octets commençant à l'octet offset le fichier mappé. Tout le temps que vous souhaitez lire une section de la mémoire qui est en dehors de la mappé fenêtre, vous avez à la carte dans une nouvelle fenêtre.

6voto

morechilli Points 4889

Le point qui vous manque, c'est que mmap est un mappage de la mémoire de la fonction qui fait correspondre un fichier dans la mémoire de l'arbitraire l'accès à travers la demande de la plage de données par tous les moyens.

Ce que vous êtes à la recherche pour les sons plus comme une sorte de fenêtre de données de classe qui présente une api vous permettant de regarder des petites fenêtres d'une grande structure de données à chaque instant. L'accès au-delà des limites de cette fenêtre ne serait pas possible autrement que par l'appel de la fenêtre de données de l'api.

C'est bien, mais ce n'est pas une carte mémoire, c'est quelque chose qui offre l'avantage d'une plus large plage de données au prix d'une plus restrictive de l'api.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X