2011-01-11 12 views
13

Sto provando a fare un po 'di tracciamento in parallelo per finire i grandi lavori batch più velocemente. A tal fine, inizio un thread per ogni trama che ho intenzione di realizzare.Matlotlib: tracciamento simultaneo in più thread

Avevo sperato che ogni thread terminasse il suo plottaggio e si chiudesse (a quanto ho capito, Python chiude i thread quando ottengono tutte le istruzioni di run()). Di seguito è riportato un codice che mostra questo comportamento.

Se la linea che crea una figura è commentata, viene eseguita come previsto. Un altro utile tidbit è che gira anche come previsto quando si genera solo un thread.

import matplotlib.pyplot as plt 
import time 
import Queue 
import threading 

def TapHistplots(): 
    ## for item in ['str1']: 
# # it behaves as expected if the line above is used instead of the one below 
    for item in ['str1','str2']: 
     otheritem = 1 
     TapHistQueue.put((item, otheritem)) 
     makeTapHist().start() 

class makeTapHist(threading.Thread): 
    def run(self): 
     item, otheritem = TapHistQueue.get() 
     fig = FigureQueue.get() 
     FigureQueue.put(fig+1) 
     print item+':'+str(fig)+'\n', 
     time.sleep(1.3) 
     plt.figure(fig) # comment out this line and it behaves as expected 
     plt.close(fig) 

TapHistQueue = Queue.Queue(0) 
FigureQueue = Queue.Queue(0) 
def main(): 
    start = time.time() 
    """Code in here runs only when this module is run directly""" 
    FigureQueue.put(1) 
    TapHistplots() 
    while threading.activeCount()>1: 
     time.sleep(1) 
     print 'waiting on %d threads\n' % (threading.activeCount()-1), 
    print '%ds elapsed' % (time.time()-start) 

if __name__ == '__main__': 
    main() 

Qualsiasi aiuto è debitamente apprezzato.

+3

Non hai effettivamente detto ciò che va male, anche se suona come una sorta di problema di concorrenza di thread. –

+0

Non sono sicuro di cosa vada storto. Non ricevo errori e un processo Python continua a funzionare. Inoltre, l'istruzione di stampa nel thread principale che dovrebbe essere disattivata ogni secondo non lo fa dopo il primo secondo. Un'occhiata nel task manager mostra che il processo continua a utilizzare molta della CPU. Purtroppo ho un'esperienza limitata nel debug serio. – Boris

+0

È tua intenzione chiamare 'makeTapHist(). Start()' più volte? Sembra che forse dovrebbe essere fuori dal giro. –

risposta

4

Per l'interfaccia pylab è disponibile una soluzione Asynchronous plotting with threads.

Senza pylab potrebbero esserci diverse soluzioni per ciascun back-end di matplotlib (Qt, GTK, WX, Tk). Il problema è che ogni toolkit della GUI ha il proprio mainloop della GUI. È possibile vedere come lo gestisce ipython.

+2

Per quanto posso dire, il collegamento fornito mostra come lavorare con una singola figura da più thread e non come creare grafici in parallelo. Come ho capito, i backend erano cruciali da prendere in considerazione quando si utilizza interattivamente matplotlib (come fa ipython). Sarei grato se potessi spiegare come si applicano a questo esempio. – Boris

+0

@Boris: il backend è importante, ad es. Http://ideone.com/J42rn produce un errore di segmentazione con il backend predefinito. – jfs

+2

btw, vesrion 'multiprocessing' è molto più veloce http://ideone.com/lFXOT – jfs

18

Perché non utilizzare solo il multiprocessing? Per quanto ne so dalla descrizione, il threading non ti aiuterà molto, comunque ...

Matplotlib già thread in modo da poter visualizzare e interagire con più figure contemporaneamente. Se si desidera accelerare l'elaborazione in batch su una macchina multicore, si avrà comunque bisogno di multiprocessing.

Come esempio di base (Attenzione: Questo creerà 20 piccoli file .png in qualunque directory lo si esegue in!)

import multiprocessing 
import matplotlib.pyplot as plt 
import numpy as np 

def main(): 
    pool = multiprocessing.Pool() 
    num_figs = 20 
    input = zip(np.random.randint(10,1000,num_figs), 
       range(num_figs)) 
    pool.map(plot, input) 

def plot(args): 
    num, i = args 
    fig = plt.figure() 
    data = np.random.randn(num).cumsum() 
    plt.plot(data) 
    plt.title('Plot of a %i-element brownian noise sequence' % num) 
    fig.savefig('temp_fig_%02i.png' % i) 

main() 
+1

Inoltre, la versione 'multiprocessing' è super veloce rispetto alla versione' threading' – jfs