2010-02-19 6 views
1

J'ai observé que, après une exception, j'ai un objet pour lequel le constructeur n'est pas appelé, ce qui provoque un verrouillage. Quelle est la meilleure façon d'améliorer la situation? L'appel del dans un bloc except serait-il la solution?Garbage collection d'objet après exception

b=BigHash(DB_DIR, url) 
meta = bdecode(b.get()) 
return meta 

b maintient un verrou qui est libéré sur la destruction (il est un objet de C de) une exception est levée par b.get().

Répondre

1

Vous devez faire quelque chose comme ceci pour vous assurer que b dans déverrouillés

b=BigHash(DB_DIR, url) 
try: 
    meta = bdecode(b.get()) 
    return meta 
finally: 
    #unlock b here 

Une façon plus propre serait si BigHash peut fonctionner comme un contexte, de sorte que vous pouvez écrire

with b as BigHash(DB_DIR, url): 
    meta = bdecode(b.get()) 
    return meta 

Vous pourrait doit ajouter du code à BigHash pour le faire fonctionner comme un contexte

+0

Est-ce que je ne peux pas utiliser "avec" ou un autre truc de langue? A partir d'un C++, je trouve problématique qu'un objet qui tombe hors de portée ne soit pas détruit. – piotr

+0

@plotr, l'objet est détruit quand il est hors de portée, mais peut-être qu'il a modifié le statut verrouillé de BigHash. Pouvez-vous montrer la source de BigHash? –

+0

Il s'agit de quelques centaines de lignes de C++, ce qui serait peu pratique. L'important est que le seau est verrouillé sur le constructeur et déverrouillé sur le destructeur. Et GC de python semble laisser l'objet qui traîne. – piotr

3

Quoi qu'il en soit, vous voulez que le verrou soit libéré - qu'une exception soit levée ou non. Dans ce cas, il est probablement préférable de libérer le verrou/supprimer b dans une clause finally::

b=BigHash(DB_DIR, url) 
try: 
    meta = bdecode(b.get()) 
finally: 
    del b # or whatever you need to do to release the lock 
return meta 

Vous pouvez également utiliser un gestionnaire de contexte - http://docs.python.org/library/stdtypes.html#typecontextmanager. Il suffit d'ajouter le code pour libérer le verrou dans la fonction BigHash.__exit__, qui sera appelé après avoir quitté le bloc with dans le code suivant:

with BigHash(DB_DIR, url) as b: 
    meta = bdecode(b.get()) 
return meta 
+0

Merci, ne pouvait pas marquer les deux comme des réponses, donc +1 – piotr

+0

Étonnamment dans Python 2.5.4 cela ne fonctionne pas avec "avec". Le destructeur n'est pas appelé. – piotr

+1

@piotr: Votre classe BigHash doit avoir la méthode '__exit__' définie pour bien jouer avec' with'. Voir http://docs.python.org/reference/datamodel.html#with-statement-context-managers –

0

Appel del sur un nom est quelque chose que vous ne devriez jamais faire prettymuch. L'appel del ne garantit rien de ce qui va arriver à l'objet sous-jacent. Vous ne devriez jamais dépendre d'une méthode __del__ pour quelque chose dont vous avez besoin. Il suffit de se débarrasser d'une référence à un objet, ce qui peut prêter à confusion lorsque vous en avez fait plus sans réfléchir. Par conséquent, del est utile pour nettoyer un espace de nom, pas pour contrôler la durée de vie des objets, et ce n'est même pas génial pour cela -la façon correcte de contrôler la durée de vie d'un nom est de le mettre dans une fonction et de l'éteindre. portée ou le mettre dans un bloc avec.

Vous devez équiper BigHash avec la possibilité de libérer le verrou explicitement, avec une méthode release ou unlock ou close. Si vous voulez utiliser ceci avec un gestionnaire de contexte (with), vous pouvez définir __exit__, qui sera appelé à un moment prévisible et utile.