2011-01-11 33 views
13

Estoy tratando de hacer un trazado en paralelo para terminar grandes trabajos por lotes más rápido. Con este fin, comienzo un hilo por cada trama que planeo hacer.Matplotlib: trazado simultáneo en múltiples hilos

Tenía la esperanza de que cada subproceso terminara su trazado y se cerrara (como yo lo entiendo, Python cierra los hilos cuando pasan por todas las instrucciones en run()). A continuación se muestra un código que muestra este comportamiento.

Si la línea que crea una figura está comentada, se ejecuta como se esperaba. Otro tidbit plausiblemente útil es que también se ejecuta como se esperaba cuando solo generas un hilo.

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

Cualquier ayuda es debidamente apreciada.

+3

Usted no ha dicho realmente lo que va mal, aunque suene algún tipo de problema de concurrencia de hilo. –

+0

No estoy seguro de qué va mal. No recibo ningún error y el proceso de Python continúa ejecutándose. Además, la instrucción de impresión en el hilo principal que debería activarse cada segundo no lo hace después del primer segundo. Una mirada en el administrador de tareas muestra que el proceso continúa usando una gran cantidad de la CPU. Tengo una experiencia limitada en depuración seria, desafortunadamente. – Boris

+0

¿Tiene intención de llamar 'makeTapHist(). Start()' varias veces? Parece que quizás debería estar fuera del circuito. –

Respuesta

4

Para la interfaz pylab hay una solución Asynchronous plotting with threads.

Sin pylab podría haber diferentes soluciones para los backends de cada matplotlib (Qt, GTK, WX, Tk). El problema es que cada kit de herramientas GUI tiene cada GUI mainloop. Se puede ver cómo ipython se ocupa de ello.

+2

Hasta donde puedo decir, el enlace proporcionado muestra cómo trabajar con una sola figura de muchos hilos, no cómo hacer gráficas en paralelo. Según lo entendí, los back-end fueron cruciales para tener en cuenta al usar matplotlib de forma interactiva (como ipython lo hace). Te agradecería si pudieras explicar cómo se aplican a este ejemplo. – Boris

+0

@Boris: el motor de fondo importa, p. Ej., Http://ideone.com/J42rn produce una falla de segmentación con el backend predeterminado. – jfs

+2

Por cierto, el 'multiprocesamiento' vesrion es mucho más rápido http://ideone.com/lFXOT – jfs

18

¿Por qué no usar multiprocesamiento? Por lo que puedo decir de su descripción, el enhebrado no lo ayudará mucho, de todos modos ...

Matplotlib ya está en subprocesos para que pueda visualizar e interactuar con varias figuras a la vez. Si desea acelerar el procesamiento por lotes en una máquina multinúcleo, necesitará multiprocesamiento independientemente.

Como un ejemplo básico (Advertencia: Esto creará 20 pequeños archivos .png en el directorio que se ejecuta en!)

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

Además, la versión 'multiprocesamiento' es superrápida en comparación con la versión' subprocesamiento ' – jfs