En este programa se ejemplifica cómo monitorear varios hilos y mostrar el progreso de cada uno en la interfase gráfica. Para saber mas sobre hilos, procesos y demás. puedes leer el post del link.
El programa utiliza unas barras de progreso (gauge) para representar cada hilo en la interfase gráfica. Cada hilo tiene un proceso, el cual consiste en contar de 0 a 100, con un retraso aleatorio de tiempo de entre 5 y 10 mili segundos en cada iteración para simular la variación de tiempos de proceso. Puedes cambiar el numero de procesos en la variable num_procesos. Corre este programa una vez y observa como las barras de progreso se llenan casi al mismo tiempo.
![]() |
semáforo desactivado |
En el código mostrado mas abajo hay 2 funciones comentadas. Estas funciones son threadLock.acquire() y threadLock.release(). Estas funciones funcionan (valga la redunancia) como un semáforo que pausa un hilo determinado mientras otro continua. Esto es útil para evitar corromper datos cuando 2 o mas hilos intentan acceder a la misma información para lectura o escritura al mismo tiempo. Des-comenta estas 2 funciones como experimento para observar como las barras de progreso se pausan entre si de modo que ya no se llenan de de forma uniforme.
![]() |
Semáforo activado |
En el código fuente te dejo comentarios comprender lo que sucede. Nesecitas la librería wxpython para correr este programa. Este programa fué probado en Python 3.7.
import wx
from time import sleep
from random import randint
from threading import Thread
from threading import Lock
from threading import current_thread
from wx.lib.newevent import NewEvent
threadLock = Lock() # descomenta threadLock.acquire() y threadLock.release()
# (mas abajo) como experimento para ver que sucede.
MandaGaugeDatos, EVT_ACTUAL_GAUG = NewEvent() # evento que se usara para monitorear hilos y actualizar gauges
num_procesos = 5 # numero de hlos (y por ende, de gauges) pon aqui los que quieras
class TestThread(Thread): # Esto es un hilo.
def __init__(self,parent,threadID):
Thread.__init__(self) # llamar al constructor de la clase
self.threadID = threadID # variable para identificar el hilo
self.parent = parent # padre de el hilo (se usa para matar hilo cunando se sierre el programa)
def run(self): # EL PROCESO
#--------------------------------------------------
# El roceso consiste en contar de 1 a 100.
# se generan retardos aleatorios para simular tiempos variantes
#--------------------------------------------------
for i in range(1,100): # Cuenta de 1 a 100%
#threadLock.acquire() # DESCOMENTA ESTO A VER QUE PASA.
slp = randint(5, 10)/1000 # generar tiempo aleatorio entre 5 y 10ms
sleep(slp) # realizar el retraso aleatorio
#-------------------------------------------------------------
# Enviar datos resultantes de cada iteracion del hilo a la GUI
# wx.postevent(parent, function) #generar evento
# MandaGaugeDatos(datos nombrados que quieras regresar)
#--------------------------------------------------
wx.PostEvent(self.parent,
MandaGaugeDatos(dato = i,
gauge = self.threadID,
thread = current_thread()))
#threadLock.release() # DESCOMENTA ESTO A VER QUE PASA.
class MainFrame(wx.Frame):
def __init__(self, parent, title =""):
super().__init__(parent, title = title , size = (500,250))
self.panel = wx.Panel(self)
self.gauges = [] # Arreglo de Gauges
threads = [] # arreglo de hilos
#---------------------------------------------
# WIDGETS
#---------------------------------------------
# llenar el arreglo de gauges
#--------------------------------------------
for gauge in range(num_procesos):
self.gauges.append(wx.Gauge(self.panel, size=(300, 20)))
#---------------------------------------------
# BINDS
#---------------------------------------------
# Conectar señal del evento emitida con la funcion correspondiente
#--------------------------------------------
self.Bind(EVT_ACTUAL_GAUG, self.on_actualizar)
#---------------------------------------------
# LAYOUT
#---------------------------------------------
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(self.panel,1, wx.CENTER|wx.ALL|wx.EXPAND)
panel_sizer = wx.BoxSizer(wx.VERTICAL)
self.panel.SetSizer(panel_sizer)
for gauge in self.gauges:
panel_sizer.Add(gauge , 0, wx.CENTER|wx.ALL|wx.EXPAND)
self.SetSizer(main_sizer)
#---------------------------------------------
# llenar arreglo de hilos e Iniciarlos todos
#---------------------------------------------
for x in range(num_procesos):
threads.append(TestThread(self, x))
threads[x].daemon = True
threads[x].start()
def on_actualizar(self, evt):
#Actualizar el gauge correspondiente en la GUI
self.gauges[evt.gauge].SetValue(evt.dato)
if __name__ == '__main__':
app = wx.App(0)
frame = MainFrame(None)
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()
No hay comentarios.:
Publicar un comentario