2011-01-07 14 views
13

¿Hay una anotación de bloqueo de python que tenga el mismo efecto que un método de python como la palabra clave "sincronizada" para los métodos de Java?anotación de método de bloqueo de python

+0

gracias por el comentario, ¿puede ser más preciso? – paweloque

+3

Depende de lo que estés haciendo. Python tiene un "bloqueo de intérprete global", por lo que solo un subproceso puede ejecutar código Python a la vez, y no puede aprovechar los múltiples núcleos. Pero si su código está esperando acceso al disco, o datos de la red, o cálculos numpy, funciona el multihilo. –

+0

Xavier, no digas tonterías. Multithreading no siempre es una mala idea.De acuerdo, tiene problemas con su GIL en sistemas multi-core para algunos códigos de CPU ... pero eso no es suficiente para llamar a todo esto una "mala idea". –

Respuesta

15

puedo asumir que ninguna característica incorporada existe en Python, pero se puede aplicar por la comprensión de cómo funciona en Java desde this enlace:

objeto Cada Java creado, incluyendo cada clase cargada, tiene un asociado cerradura o monitor. Poner el código dentro de un bloque sincronizado hace que el compilador instrucciones anexados para adquirir el bloqueo en el objeto especificado antes ejecutar el código, y lo liberan después (ya sea porque el código acabados normal o anormal). Entre la adquisición de la cerradura y liberándola, se dice que un hilo "posee" la cerradura. En el punto del Hilo A queriendo adquirir el candado, si El Hilo B ya lo posee, entonces El Hilo A debe esperar que el Hilo B lo suelte.

así que tal vez algo como esto puede trabajar:

declaración sincronizado en Java:

public class Java { 
    static private int count = 0; 

    public void increment() { 
     synchronized (this) { 
      count++; 
     } 
    } 
} 

se convirtió en:

import threading 

class Java: 
    cout = 0 
    lock = threading.RLock() 

    def increment(): 
     with Java.lock: 
      Java.cout += 1 

y sincronizada método en Java:

public class Java { 
    static private int count = 0; 

    public synchronized void increment() { 
     count ++; 
    } 
} 

se convirtió en:

import threading 

def synchronized(method): 
    """ Work with instance method only !!! """ 

    def new_method(self, *arg, **kws): 
     with self.lock: 
      return method(self, *arg, **kws) 


    return new_method 

class Java: 
    count = 0 
    lock = threading.RLock() 

    @synchronized 
    def incremenet(self): 
     Java.count += 1 

Explícito es mejor que implícito.

N.B: mi conocimiento en Java es muy limitado, y es mi primera conferencia sobre esta característica de Java así que tal vez me pierdo algo (o quizás extraño todo el punto :), espero que esta respuesta pueda ayudar a alguien.

NB: el bloqueo que he creado es una variable de clase por lo que la sincronización ocurre en el nivel de clase, si queremos hacer la sincronización en el nivel de instancia (solo) que creo que cómo lo hace java, el código anterior debe cambio.

+3

También puede usar 'with lock:' en lugar de los métodos de adquisición y liberación. –

+0

@Thomas K: gracias por la observación :) actualizado – mouad

+1

Es probable que desee agregar un 'retorno' a su decorador: no es necesario para su ejemplo, pero le permite reutilizar el decorador con un método que devuelve algo. Además, no existe un motivo particular para acceder explícitamente al bloqueo a través de la clase, siempre que no se le asigne puede acceder a la variable de clase a través de la instancia. 'con self.lock: método de retorno (self, * args, ** kws)' – Duncan

1

A veces uso un decorador de esta manera:

def synchronized(f): 
    @functools.wraps(f) 
    def wrapper(self, *args, **kwargs): 
     try: 
      _ = self._lock 
     except AttributeError: 
      self._lock = threading.Lock() 

     with self._lock: 
      return f(self, *args, **kwargs) 
    return wrapper 

Esta solución tiene una condición de carrera cuando se llama al método decorada por primera vez, sin embargo. La forma más sencilla de evitar este problema es llamar a un método sincronizado cuando no hay otros hilos ejecutándose primero, o asignar el self._lock manualmente en __init__