2010-06-25 9 views
6

Tengo problemas de estancamiento con este pedazo de código:estancamientos Python multiprocessing.Queue en PUT y GET


def _entropy_split_parallel(data_train, answers_train, weights): 
    CPUS = 1 #multiprocessing.cpu_count() 
    NUMBER_TASKS = len(data_train[0]) 
    processes = [] 

    multi_list = zip(data_train, answers_train, weights) 

    task_queue = multiprocessing.Queue() 
    done_queue = multiprocessing.Queue() 

    for feature_index in xrange(NUMBER_TASKS): 
     task_queue.put(feature_index) 

    for i in xrange(CPUS): 
     process = multiprocessing.Process(target=_worker, 
       args=(multi_list, task_queue, done_queue)) 
     processes.append(process) 
     process.start() 

    min_entropy = None 
    best_feature = None 
    best_split = None 
    for i in xrange(NUMBER_TASKS): 
     entropy, feature, split = done_queue.get() 
     if (entropy < min_entropy or min_entropy == None) and entropy != None: 
      best_feature = feature 
      best_split = split 

    for i in xrange(CPUS): 
     task_queue.put('STOP') 

    for process in processes: 
     process.join() 

    return best_feature, best_split 


def _worker(multi_list, task_queue, done_queue): 
    feature_index = task_queue.get() 
    while feature_index != 'STOP': 
     result = _entropy_split3(multi_list, feature_index) 
     done_queue.put(result) 
     feature_index = task_queue.get() 

Cuando ejecuto mi programa, que funciona bien para varias carreras a través _entropy_split_parallel, pero al final los puntos muertos. El proceso principal está bloqueando en done_queue.get(), y el proceso de trabajo está bloqueando en done_queue.put(). Como la cola está siempre vacía cuando esto sucede, se espera que se bloquee en get. Lo que no entiendo es por qué el trabajador está bloqueando en put, ya que la cola obviamente no está llena (¡está vacía!). Probé los argumentos de las palabras clave block y timeout, pero obtuve el mismo resultado.

Estoy usando el backport de multiproceso, ya que estoy atascado con Python 2.5.


EDIT: Parece que yo también estoy cuestiones de punto muerto con uno de los ejemplos proporcionados con el módulo de multiprocesamiento. Es el tercer ejemplo de la parte inferior here. El bloqueo de seguridad solo parece ocurrir si invoco el método de prueba muchas veces. Por ejemplo, cambiar el fondo de la secuencia de comandos para esto:


if __name__ == '__main__': 
    freeze_support() 
    for x in xrange(1000): 
     test() 

EDIT: Sé que esto es una cuestión de edad, pero las pruebas muestran que esto ya no es un problema en las ventanas con Python 2.7. Probaré Linux e informaré.

Respuesta

0

Este problema desapareció con las versiones más nuevas de Python, así que supongo que fue un problema con el backport. De todos modos, ya no es un problema.

4

Creo que el problema es el subproceso principal que une un subproceso secundario al que ha pasado una cola. Esto se discute en el módulo de multiprocesamiento programming guidelines section.

En cualquier caso, encontré el mismo síntoma que usted describe, y cuando reformulé mi lógica para que el hilo maestro no se uniera a los hilos secundarios, no hubo interbloqueo. Mi lógica refactorizada implicaba conocer la cantidad de elementos que debía obtener de los resultados o la cola "realizada" (que puede predecirse en función del número de subprocesos o la cantidad de elementos en la cola de trabajos, etc.) y de los bucles. infinitamente hasta que todos estos fueron recogidos.

ilustración "juguete" de la lógica:

num_items_expected = figure_it_out(work_queue, num_threads) 
items_received = [] 
while len(items_received) < num_items_expected: 
    items_received.append(done_queue.get()) 
    time.sleep(5) 

La lógica anterior evita la necesidad de que el hilo de los padres a unirse al hilo hijo, sin embargo, permite que el hilo de los padres para bloquear hasta que todos los niños terminen. Este enfoque evitó mis problemas de interbloqueo.

+0

Creo que todas las colas deben estar vacías cuando se unen los procesos, por lo que esto no debería ser un problema. Además, el proceso maestro es deadlocking en put, en lugar de join. Acabo de actualizar Python (me quedé con una versión anterior), así que voy a probar esto de nuevo. – ajduff574

+0

@ajduff en mi caso, el punto muerto no ocurrió en la unión, sino que también se colocó, excepto que el put estaba en el hilo hijo. Además, en mi caso, la cola que estaba siendo colocada estaba vacía. Así que creo que vale la pena intentarlo (es decir, evitar el hilo maestro que une los hilos secundarios) en su caso también. – Jeet