2009-02-28 7 views
1

Je suis en train d'essayer de mettre au banc d'essai le Amazon S3 python library pour permettre la manipulation en morceaux de gros fichiers. En ce moment, il fait un "self.body = http_response.read()", donc si vous avez un fichier 3G, vous allez tout lire en mémoire avant de prendre le contrôle.Python: joindre efficacement des blocs d'octets en un seul gros morceau?

Mon approche actuelle consiste à essayer de garder l'interface pour la bibliothèque identique, mais de fournir un rappel après avoir lu chaque morceau de données. Quelque chose comme ce qui suit:

data = [] 
while True: 
    chunk = http_response.read(CHUNKSIZE) 
    if not chunk: 
     break 
    if callback: 
     callback(chunk) 
    data.append(chunk) 

Maintenant, je dois faire quelque chose comme:

self.body = ''.join(data) 

est-rejoindre la bonne façon de le faire ou est-il une autre façon (meilleure) de mettre tous les morceaux ensemble?

Répondre

2

hm - Quel problème tentez-vous de résoudre? Je soupçonne que la réponse dépend de ce que vous essayez de faire avec les données. Comme en général vous ne voulez pas un fichier 3Gb entier en mémoire, je ne stockerais pas les morceaux dans un tableau, mais je passerais par-dessus la réponse http et je l'écrirais directement sur le disque, dans un fichier temporaire ou persistant utilisant le méthode write() normale sur un descripteur de fichier approprié. Si vous voulez deux copies des données en mémoire, votre méthode nécessitera au moins 6Gb pour votre hypothétique fichier 3Gb, ce qui est vraisemblablement significatif pour la plupart des matériels.

Je sais que les méthodes de jointure de tableau sont rapides et tout cela, mais comme il s'agit d'un processus vraiment limité par les RAM, peut-être que vous voulez trouver un moyen de le faire mieux? StringIO (http://docs.python.org/library/stringio.html) crée des objets chaîne pouvant être ajoutés en mémoire; le python pur, puisqu'il doit fonctionner avec des chaînes immuables, utilise simplement votre astuce de jointure de tableaux en interne, mais le cStringIO basé sur c peut en fait s'ajouter à un tampon de mémoire interne. Je n'ai pas son code source à portée de main, ce qui me permettrait de vérifier. Si vous souhaitez effectuer une analyse sur les données et que vous souhaitez réellement les conserver en mémoire avec un minimum de temps système, vous pouvez envisager certains des objets de tableaux d'octets de Numeric/NumPy comme alternative à StringIO. Ce sont des codes haute performance optimisés pour les grandes baies et peuvent être ce dont vous avez besoin.

comme un exemple utile, pour un objet fichier de manipulation à usage général qui a approche de mémoire efficace iterator convivial vous pouvez vérifier le code de gestion morceau de fichier django obeject: http://code.djangoproject.com/browser/django/trunk/django/core/files/base.py.

+0

Excellent point concernant le besoin de 6 Go au lieu de 3 avec ma méthode ci-dessus. Je veux traiter les morceaux et m'en débarrasser (il suffit de les écrire sur le disque dans ce cas), mais je voulais aussi préserver la sémantique existante qui donne accès aux données en mémoire. Je pourrais devoir renoncer à ce dernier. – Parand

0

En python3, bytes les objets sont distincts de str, mais je ne sais pas pourquoi il y aurait quelque chose de mal à cela.

0

join semble bien si vous avez vraiment besoin de mettre l'ensemble de la chaîne ensemble, mais alors vous venez de stocker tout dans la RAM de toute façon. Dans une situation comme celle-ci, j'essaierais de voir s'il y a un moyen de traiter chaque partie de la chaîne, puis de rejeter la partie traitée, de sorte que vous ne devez conserver qu'un nombre fixe d'octets en mémoire à la fois. C'est généralement le point de l'approche de rappel. (Si vous ne pouvez traiter qu'une partie d'un bloc à la fois, utilisez un tampon comme file d'attente pour stocker les données non traitées.)

+0

D'accord, mais j'essaie de préserver l'API existante et qui nécessite l'ensemble de la chose en mémoire. Idéalement, le corps serait un générateur au lieu d'être un morceau d'octets, laissant l'utilisateur traiter avec eux comme ils veulent ... – Parand

3

'' join() est la meilleure méthode pour joindre des blocs de données. L'alternative se résume à une concaténation répétée, qui est O (n ** 2) en raison de l'immutabilité des chaînes et de la nécessité de créer plus à chaque concaténation. Étant donné, cette concaténation répétée est optimisée par les versions récentes de CPython si elle est utilisée avec + = pour devenir O (n), mais cette optimisation lui donne seulement un équivalent approximatif de '' .join() de toute façon, explicitement O (n) le nombre d'octets.

Questions connexes