2011-03-03 15 views
15

Una pregunta rápida, es de esperar ...Python condicional "con" diseño de la cerradura

que estoy tratando de hacer un poco de bloqueo compartido utilizando con declaraciones

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" 

Eso tiene sentido? Yo, básicamente, solamente quiero hacer el con SI * i no tiene aún el bloqueo ..

Además de ser capaz de lograr esto, es que un mal diseño? ¿Debería simplemente adquirir/liberarme?

Esto parece como una de esas preguntas pedo cerebral ..

+1

Tiene un olor código. – zzzzBov

+0

Ya no más, voy a utilizar RLock – Nix

Respuesta

30

sólo tiene que utilizar un threading.RLock que se re-entrante lo que significa que se puede adquirir múltiples veces por el mismo hilo.

http://docs.python.org/library/threading.html#rlock-objects

Para mayor claridad, la RLock se utiliza en las declaraciones with, al igual que en el código de ejemplo:

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 cuanto a si es o no es un mal diseño, necesitaríamos más contexto. ¿Por qué ambas funciones necesitan adquirir el bloqueo? ¿Cuándo es func2 llamado por algo que no sea func1?

+1

la capacidad de utilizar la sentencia with elimina una gran cantidad de código de placa de la caldera ... – Nix

+0

No importa, esto funciona perfectamente. Gracias. – Nix

+1

@Nix “Todos los objetos proporcionados por este módulo que tienen acquire() y liberación() métodos se pueden utilizar como gestores de contexto para una sentencia with” –

0

Usando con la declaración es mejor que sólo acquire() y release() funciones. De esta forma, si ocurre un error, se liberarán los bloqueos.

+0

se puede hacer con condicionalmente? – Nix

+0

No se pueden hacer declaraciones condicionales, pero algunos objetos admiten la asignación a través de la instrucción with. Por ejemplo 'con ("x.txt") abierta como f: f.read de impresión()' –

0

La sentencia with es una gran manera de poner en práctica de bloqueo, como un patrón de bloqueo es la adquisición de recursos perfecto. Sin embargo, su ejemplo actual no funcionará, necesitará una instrucción if en torno a la declaración with dentro de algoElse().

4

El pitón or es short circuiting para que pueda realizar el bloqueo condicional:

def somethingElse(self, hasLock = False): 
    #I want this to be conditional... 
    with hasLock or self.my_lock: 
      print 'i hate hello worlds' 

Por desgracia, no es así de fácil, ya que un valor lógico no es una respuesta válida a partir de una declaración with. Tendrá que crear una clase con el __enter__ y __exit__ para envolver el valor booleano True.

Aquí es una posible implementación que no he probado.

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' 

Se trata de una gran cantidad de texto modelo para algo tan simple, por lo que la solución RLock parece un ganador. Sin embargo, esta solución podría ser útil en un contexto diferente.

+0

Este sería un buen momento para utilizar [ContextManager] (http://docs.python.org/library/contextlib.html#contextlib.contextmanager). –

+1

Creo que esto funcionaría, pero RLock hace lo que necesito de fábrica. Gracias. – Nix

+0

@jleedev, gracias, me olvidé de contextmanager. Lamentablemente, no creo que funcione en este contexto, ya que solo desea ajustar el valor verdadero, no el falso. –

1

Por qué no:

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" 

Nótese que si bien someMethod y somethingElse son idénticos en mi solución, en general, serían diferentes. Puede poner otro contenedor alrededor de somethingNoLock para que la adquisición y liberación de bloqueo no se repita varias veces.

Esto es mucho más simple y directo. El hecho de que el martillo de bloqueo reentrante esté disponible, no recomendaría su uso cuando hay una manera más directa y menos frágil de clavarlo.

La crítica más específica de RLOCK es que la línea que crea la re-entrante de bloqueo está lejos del código que está adquiriendo la cerradura de una manera reentrante. Esto es levemente frágil si alguien dice que fusiona el bloqueo de reentrada con otro bloqueo que no es reentrante o cambia la línea que crea el candado.