J'essaie de faire un verrouillage partagé avec des instructions
def someMethod(self, hasLock = False):
with self.my_lock:
self.somethingElse(hasLock=True)
def somethingElse(self, hasLock = False):
#I want this to be conditional...
with self.my_lock:
print 'i hate hello worlds"
C'est logique? Je veux simplement faire avec si je n'ai pas encore le verrou.
En plus de pouvoir accomplir cela, est-ce une mauvaise conception? Dois-je simplement m'acquérir/me libérer?
Utilisez simplement un threading.RLock
qui est rentrant, ce qui signifie qu'il peut être acquis plusieurs fois par le même thread.
http://docs.python.org/library/threading.html#rlock-objects
Pour plus de clarté, le RLock
est utilisé dans les instructions with
, comme dans votre exemple de code:
lock = threading.RLock()
def func1():
with lock:
func2()
def func2():
with lock: # this does not block even though the lock is acquired already
print 'hello world'
En ce qui concerne la mauvaise conception ou non, nous aurions besoin de plus de contexte. Pourquoi les deux fonctions doivent-elles acquérir le verrou? Quand est func2
appelé par autre chose que func1
?
Le Python or
est court-circuitage afin que vous puissiez rendre le verrouillage conditionnel:
def somethingElse(self, hasLock = False):
#I want this to be conditional...
with hasLock or self.my_lock:
print 'i hate hello worlds'
Malheureusement, ce n'est pas si simple, car un booléen n'est pas un retour valide à partir d'une instruction with
. Vous devrez créer une classe avec le __enter__
et __exit__
pour encapsuler la valeur booléenne True
.
Voici une implémentation possible que je n'ai pas testée.
from contextlib import contextmanager
@contextmanager
def withTrue():
yield True
def withbool(condition):
if condition:
return withTrue()
return False
def somethingElse(self, hasLock = False):
with withbool(hasLock) or self.my_lock():
print 'i hate hello worlds'
C'est beaucoup de passe-partout pour quelque chose de si simple, donc la solution RLock ressemble à un gagnant. Cette solution pourrait cependant être utile dans un contexte différent.
Pourquoi pas:
def someMethod(self):
with self.my_lock:
self.somethingNoLock()
def somethingElse(self):
with self.my_lock:
self.somethingNoLock()
def somethingNoLock(self):
print 'i hate hello worlds"
Notez que si someMethod
et somethingElse
sont identiques dans ma solution, en général ils seraient différents. Vous pouvez placer un autre wrapper autour de somethingNoLock
afin que l'acquisition et la libération du verrou ne soient pas répétées plusieurs fois.
C'est beaucoup plus simple et direct. Tout simplement parce que le marteau de verrouillage rentrant est disponible, je ne recommanderais pas de l'utiliser lorsqu'il existe un moyen plus simple et moins fragile de le clouer.
La critique plus spécifique de rlock est que la ligne qui crée le verrou rentrant est loin du code qui acquiert le verrou de manière rentrante. Ceci est légèrement fragile si quelqu'un dit fusionne le verrou rentrant avec un autre verrou qui n'est pas rentrant ou change autrement la ligne qui crée le verrou.
Il est préférable d'utiliser l'instruction with que les fonctions acquire()
et release()
. De cette façon, si une erreur se produit, les verrous seront libérés.
L'instruction with est un excellent moyen d'implémenter le verrouillage, car le verrouillage est un modèle d'acquisition de ressources parfait. Cependant, votre exemple actuel ne fonctionnera pas, vous aurez besoin d'une instruction if autour de l'instruction with dans quelque chose d'Else ().