2014-04-24 6 views
0

J'ai un grand dictionnaire dont la structure ressemble à:cPickle.load() en python consomme une grande mémoire

dcPaths = {'id_jola_001': CPath instance} 

où cpath est une classe d'auto-défini:

class CPath(object): 
    def __init__(self): 
     # some attributes 
     self.m_dAvgSpeed = 0.0 
     ... 
     # a list of CNode instance 
     self.m_lsNodes = [] 

où m_lsNodes est une liste des Nœuds-C:

class CNode(object): 
    def __init__(self): 
     # some attributes 
     self.m_nLoc = 0 

     # a list of Apps 
     self.m_lsApps = [] 

ici, m_lsApps est une liste de CApp, qui est une autre classe d'auto-défini:

class CApp(object): 
    def __init__(self): 
     # some attributes 
     self.m_nCount= 0 
     self.m_nUpPackets = 0 

Je sérialiser ce dictionnaire en utilisant cPickle:

def serialize2File(strFileName, strOutDir, obj): 
    if len(obj) != 0: 
     strOutFilePath = "%s%s" % (strOutDir, strFileName) 
     with open(strOutFilePath, 'w') as hOutFile: 
      cPickle.dump(obj, hOutFile, protocol=0) 
     return strOutFilePath 
    else: 
     print("Nothing to serialize!") 

Il fonctionne très bien et la taille du fichier sérialisé est d'environ 6.8GB. Cependant, lorsque je tente de désérialiser cet objet:

def deserializeFromFile(strFilePath): 
    obj = 0 
    with open(strFilePath) as hFile: 
     obj = cPickle.load(hFile) 
    return obj 

Je trouve qu'il consomme plus de mémoire 90GB et prend beaucoup de temps.

  1. pourquoi cela se produirait-il?
  2. Y a-t-il un moyen de l'optimiser?

BTW, j'utilise python 2.7.6

+0

Combien de mémoire le processus a-t-il consommé avant de transférer les données dans le pickle? – WeaselFox

+0

Cela peut dépendre de la façon dont les classes stockées sont définies, donc cela vous aidera si vous ajoutez le code. – bereal

+0

Etes-vous sûr que c'est la désérialisation? La sérialisation est connue pour prendre un peu plus de mémoire pour gérer les références cycliques. – KillianDS

Répondre

0

Vous pouvez essayer de spécifier le protocole de pickle; le plus rapide est -1 (ce qui signifie: le dernier protocole , pas de problème si vous décapez et défaites avec la même version Python).

cPickle.dump(obj, file, protocol = -1) 

EDIT: Comme indiqué dans les commentaires: load détecte le protocole lui-même.

cPickle.load(obj, file) 
+0

Puis-je sauvegarder avec protocol = 0 et charger avec protocol = -1? Parce que j'ai déjà jeté des données avec protocole = 0 et le problème est maintenant comment puis-je le recharger? En outre, je ne trouve pas le paramètre de protocole dans cPickle.load(). –

+0

@ice_lin 'load' détecte le protocole lui-même, vous ne pouvez le spécifier que sur' dump'/'dumps'. Mais le protocole 0 n'est pas très efficace et pourrait au moins partiellement expliquer les problèmes que vous voyez. – KillianDS

+0

@ice_lin: charger vos données sauvegardées avec le protocole 0, puis les récupérer avec protocol = -1 ... – mguijarr

0

Lorsque vous stockez des objets python complexes, python stocke habituellement beaucoup de données inutiles (voir la propriété d'objet __dict__). Afin de réduire la consommation de mémoire des données non sérialisées, vous ne devriez décaper que des python natifs. Vous pouvez y parvenir en implémentant facilement certaines méthodes sur vos classes: object.__getstate__() et object.__setstate__(state).

Voir sur la documentation python.

+1

That '__dict__' est un moyen standard de représenter des objets python, il serait là aussi avant le décapage, donc cela n'expliquerait pas une augmentation de la mémoire. – KillianDS

+1

@KillianDS mais beaucoup de documents référencés sont également sérialisés car il est impossible de mettre à jour les références aux objets personnalisés vers leurs nouveaux homologues dans un nouvel environnement. Pickle fait un peu de magie pour minimiser cet effet (résolution des types inspectant au niveau du module), mais les instances non désirées (comme les singletons) sont sérialisées et dupliquées lors du démontage. – ergoithz

Questions connexes