2012-06-28 19 views
14

Después de un breve debate con alguien sobre el manejo de excepciones en Python - provocado por la manipulación de un objeto de cola - que pensé en tirar por ahí ...Python: Queue.Empty manejo de excepciones

MÉTODO 1:

import Queue 

q = Queue.Queue() 

try: 
    task=q.get(False) 
    #Opt 1: Handle task here and call q.task_done() 
except Queue.Empty: 
    #Handle empty queue here 
    pass 

#Opt2: Handle task here and call q.task_done() 

MÉTODO 2:

import Queue 

q = Queue.Queue() 

if q.empty(): 
    #Handle empty queue here 
else: 
    task = q.get() 
    #Handle task here 
    q.task_done() 

un argumento es que el método 1 es incorrecto porque estar vacía la cola no es un error, y por lo tanto no debe ser manejado usando Queue.Empty excepción. Además, podría hacer que la depuración sea más difícil cuando se codifica de esta manera si se considera que la parte de manejo de tareas podría ser potencialmente grande.

El otro argumento es que de cualquier manera es aceptable en Python y que el manejo de la tarea fuera del try/except podría ayudar depuración si la manipulación tarea es grande, aunque de acuerdo en que este puede tener un aspecto feo que utilizando el método 2.

Opiniones?

ACTUALIZACIÓN: Un poco más de información después de la respuesta 1 apareció .... El debate se inició después de que el método 1 se utilizaba en algún código multiproceso. En ese caso, el código adquirirá el bloqueo (de un objeto Threading.Lock) y lo liberará una vez que la tarea que devolvió o Queue.Empty se haya lanzado

ACTUALIZACIÓN 2: Nos resultaba desconocido que el el objeto queue era thread safe. Parece que intenta/¡excepto que es el camino a seguir!

+1

No veo cómo un candado cambia la respuesta, tampoco entiendo por qué necesita un candado, la cola ya es segura para subprocesos. –

Respuesta

26

El método 2 es incorrecto porque está realizando una operación en dos pasos cuando podría hacerse en uno. En el método 2, comprueba si la cola está vacía, y luego (muy pronto, pero aún más tarde), intente obtener el artículo. ¿Qué sucede si tiene dos hilos tirando elementos de la cola? El get() todavía podría fallar con una cola vacía. ¿Qué ocurre si se agrega un artículo a la cola después de que verificó que estaba vacío? Estas son el tipo de pequeñas ventanas de oportunidad donde los errores ingresan al código concurrente.

Hazlo en un solo paso, es de lejos la mejor opción.

import Queue 

q = Queue.Queue() 

try: 
    task = q.get(False) 
except Queue.Empty: 
    # Handle empty queue here 
    pass 
else: 
    # Handle task here and call q.task_done() 

No se cuelguen de "las excepciones deben ser errores". Las excepciones son simplemente otro canal de comunicación, úsalas. Use la cláusula "else" aquí para reducir el alcance de la cláusula de excepción.

3

Si esto es multiproceso/multiprocessed código (como es una buena razón para usar colas de todos modos), entonces definitivamente el método 1. Entre el q.empty() llamada y la llamada q.get(), la jota de corazones podría haber robado sus tartas!

+0

El debate se inició después de que se utilizara el método 1 en algún código multiproceso. En cuyo caso, el código adquirirá el bloqueo (de un objeto Threading.Lock) y lo liberará una vez que la tarea que devolvió o Queue.Empty se haya emitido ... ¿la misma opinión? – user1014903

+0

mantenga el código de manejo de errores lo más ajustado posible - llame a 'get' y revise el error inmediatamente después de eso. no es necesario incrustar el resto del código en el intento ... –

2

Un argumento es que el método 1 es incorrecto porque estar vacía la cola no es un error, y por lo tanto no debe ser manejado usando Queue.Empty excepción

Una excepción no es necesariamente un "error" , es un mecanismo de control de flujo general, y de hecho se usa de esa manera en algunos casos (SysExit, StopIteration, etc.).

La buena pregunta aquí es: cuál será el caso más común: cola vacía o no vacía. A menos que sepa con certeza, quiere AskBeforeYouLeap, porque probablemente sea mucho más barato.