2010-06-25 8 views
6

Sto avendo problemi di stallo con questo pezzo di codice:deadlock Python multiprocessing.Queue su put e ottenere


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() 

Quando eseguo il mio programma, che funziona bene per diversi attraversa _entropy_split_parallel, ma alla fine deadlock. Il processo principale sta bloccando su done_queue.get() e il processo di lavoro sta bloccando su done_queue.put(). Poiché la coda è sempre vuota quando ciò accade, è previsto il blocco su get. Quello che non capisco è il motivo per cui il lavoratore sta bloccando su put, poiché ovviamente la coda non è piena (è vuota!). Ho provato gli argomenti delle parole chiave block e timeout, ma ottengo lo stesso risultato.

Sto utilizzando il backport multiprocessing, poiché sono bloccato con Python 2.5.


MODIFICA: Sembra che si verifichino anche problemi di deadlock con uno degli esempi forniti con il modulo di multiprocessing. È il terzo esempio dal basso here. Il deadlock sembra solo verificarsi se chiamo il metodo di prova più volte. Ad esempio, la modifica nella parte inferiore dello script per questo:


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

EDIT: So che questa è una vecchia questione, ma i test dimostra che questo non è più un problema su finestre con Python 2.7. Proverò Linux e riferirò.

risposta

0

Questo problema è andato via con le versioni più recenti di Python, quindi presumo fosse un problema con il backport. Ad ogni modo, non è più un problema.

4

Penso che il problema sia il thread padre che unisce un thread figlio a cui ha passato una coda. Questo è discusso il modulo programming guidelines section del modulo multiprocessing.

In ogni caso, ho riscontrato lo stesso sintomo che si descrive, e quando ho refactored la mia logica in modo che il thread principale non ha unito i thread figlio, non c'era deadlock. La mia logica refactored implicava conoscere il numero di elementi che dovrei ottenere dai risultati o dalla coda "completata" (che può essere prevista in base al numero di thread secondari o al numero di elementi nella coda di lavoro, ecc.) E al ciclo infinitamente fino a quando tutti questi sono stati raccolti.

illustrazione "giocattolo" della logica:

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 logica sopra evita la necessità per il thread genitore di aderire al thread figlio, ma permette al filo genitore di bloccare fino a quando tutti i bambini sono fatti. Questo approccio ha evitato i miei problemi di deadlock.

+0

Penso che tutte le code dovrebbero essere vuote quando i processi vengono uniti, quindi questo non dovrebbe essere un problema. Inoltre, il processo principale è deadlocking su put, piuttosto che join. Ho appena aggiornato Python (ero bloccato con una vecchia versione), quindi lo verificherò di nuovo. – ajduff574

+0

@ajduff nel mio caso, il deadlock non si è verificato nel join, ma anche il put, tranne che il put era nel thread secondario. Inoltre, nel mio caso, la coda che era stata inserita era vuota. Quindi penso che valga la pena sparare (ad esempio, evitando il thread principale che unisce i thread figli) nel tuo caso. – Jeet