Foros del Web » Programando para Internet » Python »

[Resuelto] problema con hilos (malditos hilos en python xD)

Estas en el tema de [Resuelto] problema con hilos (malditos hilos en python xD) en el foro de Python en Foros del Web. el tema es asi, necesito que un hilo se inicie y se pare en diversas partes del programa. como deben saber python no tiene un ...
  #1 (permalink)  
Antiguo 07/08/2010, 13:38
 
Fecha de Ingreso: febrero-2010
Mensajes: 10
Antigüedad: 14 años, 2 meses
Puntos: 0
[Resuelto] problema con hilos (malditos hilos en python xD)

el tema es asi, necesito que un hilo se inicie y se pare en diversas partes del programa. como deben saber python no tiene un buen manejo de hilos (por lo que lei por toda internet) con lo que por ejemplo no se puede parar un hilo desde fuera del hilo.
al parar el hilo (con un bucle como lei en varios lados) y al volverlo a iniciar, me tira un error diciendo de que el hilo ya esta iniciado, incluso poniendole un if not hilo.isAlive()

aca un codigo simplificado:
Código:
import sys
import os
import threading, time

class MainWindow():
    
    def __init__(self):
        # t es un hilo
        self.t = threading.Thread(target=self.hilo)
        #como python no brinda una forma de parar ciclos desde afuera necesitamos una variable :S, pero bueh
        self.parar=True
        print "creo hilo por primera vez"
        self.crearHilo()
        print "creo un hilo sin parar el anterior"
        self.crearHilo()
        print "paro el hilo, espero 5 seg y vuelvo a crear"
        self.parar=True
        time.sleep(5)
        self.crearHilo()
    
    def crearHilo(self):
        if self.t.isAlive():
            print "hilo activo, no inicio"
        else:
            self.parar=False
            print "hilo desactivado, inicio"
            self.t.start()
    
    def hilo(self):
        while (not self.parar):
            print "se esta ejecutando el hilo"
            time.sleep(2)
        return

if __name__ == "__main__":
    oa=MainWindow()
me imprime esto la consola cuando lo ejecuto:
Código:
creo hilo por primera vez
hilo desactivado, inicio
se esta ejecutando el hilo
 creo un hilo sin parar el anterior
hilo activo, no inicio
paro el hilo, espero 3 seg y vuelvo a crear
hilo desactivado, inicio
Traceback (most recent call last):
  File "__init__.py", line 38, in <module>
    oa=MainWindow()
  File "__init__.py", line 21, in __init__
    self.crearHilo()
  File "__init__.py", line 29, in crearHilo
    self.t.start()
  File "/usr/lib/python2.6/threading.py", line 467, in start
    raise RuntimeError("thread already started")
RuntimeError: thread already started
alguno sabe por que?
desde ya muchas gracias

Última edición por theteam; 08/08/2010 a las 12:18
  #2 (permalink)  
Antiguo 07/08/2010, 16:47
Avatar de razpeitia
Moderador
 
Fecha de Ingreso: marzo-2005
Ubicación: Monterrey, México
Mensajes: 7.321
Antigüedad: 19 años, 1 mes
Puntos: 1360
Respuesta: problema con hilos (malditos hilos en python xD)

Esto no se debe al soporte de hilos en python, esto se debe a que solo tienes un hilo nunca creaste otro hilo. Solo tienes el hilo principal y el hilo t.

Te dejo un ejemplo sencillo de como manejar hilos (ademas de una comparación):

Sin Hilos
Código Python:
Ver original
  1. import time
  2.  
  3. def f(num):
  4.     time.sleep(1)
  5.     print "Hilo %d" % num
  6.    
  7. for i in range(10):
  8.     f(i)

Con Hilos
Código Python:
Ver original
  1. import sys
  2. import threading, time
  3.  
  4. class Thread(threading.Thread):
  5.     def __init__(self, num):
  6.         threading.Thread.__init__(self)
  7.         self.num = num
  8.  
  9.     def run(self):
  10.         time.sleep(1)
  11.         sys.stdout.write("Hilo %d\n" % self.num)
  12.  
  13. for i in range(10):
  14.     t = Thread(i)
  15.     t.start()
  #3 (permalink)  
Antiguo 07/08/2010, 18:03
 
Fecha de Ingreso: febrero-2010
Mensajes: 10
Antigüedad: 14 años, 2 meses
Puntos: 0
Respuesta: problema con hilos (malditos hilos en python xD)

vos decis que no se puede iniciar y parar un hilo cuantas veces quiera por mas que siempre mantenga solo una iniciacion del hilo a la vez? (fijate que yo paro el hilo y cuando el hilo ya finalizo lo vuelvo a iniciar)
en caso de que lo anterior sea afirmativo, crear varios hilos para esto, no seria ineficiente? o cuando termina un hilo no queda en memoria?

probe este codigo y anda, pero me gustaria que no queden hilos colgados en memoria:
(lo que hago es antes de hacer hilo.start(), hago: hilo=threading.Thread(target=self.hilo)
Código Python:
Ver original
  1. class MainWindow():
  2.    
  3.     def __init__(self):
  4.         # t es un hilo
  5.         self.t = threading.Thread(target=self.hilo)
  6.         #como python no brinda una forma de parar ciclos desde afuera necesitamos una variable :S, pero bueh
  7.         self.parar=True
  8.         print "creo hilo por primera vez"
  9.         self.crearHilo()
  10.         print "creo un hilo sin parar el anterior"
  11.         self.crearHilo()
  12.         print "paro el hilo, espero 5 seg y vuelvo a crear"
  13.         self.parar=True
  14.         time.sleep(10)
  15.         self.crearHilo()
  16.    
  17.     def crearHilo(self):
  18.         if self.t.isAlive():
  19.             print "hilo activo, no inicio"
  20.         else:
  21.             self.parar=False
  22.             print "hilo desactivado, inicio"
  23.             # t es un hilo
  24.             self.t = threading.Thread(target=self.hilo)
  25.             self.t.start()
  26.    
  27.     def hilo(self):
  28.         while (not self.parar):
  29.             print "se esta ejecutando el hilo"
  30.             time.sleep(2)
  31.         print "se esta acabando el hilo"
  32.         return
  33.  
  34. if __name__ == "__main__":
  35.     oa=MainWindow()


en cuanto a la forma de implementar hilos, tanto heredando de threads (como me propusiste vos) como haciendo como hago yo, tengo entendido que es lo mismo, o por lo menos es valido hacerlo de las dos formas.
se que para el ejemplo que puse es trivial los hilos, pero lo simplifique para no enredarme con otras cosas y centrarme en el problema de los hilos y para que ustedes entiendan el codigo sin tener que leer mucho codigo.

gracias por responder!!
  #4 (permalink)  
Antiguo 07/08/2010, 19:16
Avatar de razpeitia
Moderador
 
Fecha de Ingreso: marzo-2005
Ubicación: Monterrey, México
Mensajes: 7.321
Antigüedad: 19 años, 1 mes
Puntos: 1360
Respuesta: problema con hilos (malditos hilos en python xD)

Simplificando tu problema, sin utilizacion de clases para que sea realmente facil de leer

Código Python:
Ver original
  1. import threading
  2. from time import sleep
  3.  
  4. stop = True #Variable de control
  5.  
  6. def run(): #Esto es lo que hace el hilo
  7.     global stop
  8.     while not stop:
  9.         print "Hilo en ejecucion por 2s"
  10.         sleep(2)
  11.  
  12. def execThread(thread):
  13.     global stop
  14.     if thread.isAlive():
  15.         print "Hilo Ejecutandose"
  16.     else:
  17.         stop = False
  18.         print "Hilo antes o despues de ejecutarse"
  19.         thread.start()
  20.        
  21. t = threading.Thread(target=run) #Aqui creas un hilo
  22. execThread(t)
  23. execThread(t)
  24. stop = True
  25. sleep(5)
  26. execThread(t)

Ademas citando a la documentación:
Cita:
Iniciado por pydoc
This method will raise a RuntimeException if called more than once on the same thread object.
Cita:
Iniciado por pydoc-es
Este metodo lanzara la excepcion RuntimeError si es llamada mas de una vez en el mismo objeto thread.
En pocas palabras, un thread(hilo) una ejecución.
  #5 (permalink)  
Antiguo 07/08/2010, 21:44
 
Fecha de Ingreso: febrero-2010
Mensajes: 10
Antigüedad: 14 años, 2 meses
Puntos: 0
Respuesta: problema con hilos (malditos hilos en python xD)

eso quedo mucho mas prolijo, gracias :)

pero si lo ejecutas tira el error que comentaba en el principio, para solucionarlo quedaria asi:
Código Python:
Ver original
  1. import threading
  2. from time import sleep
  3.  
  4. stop = True #Variable de control
  5.  
  6. def run(): #Esto es lo que hace el hilo
  7.     global stop
  8.     while not stop:
  9.         print "Hilo en ejecucion por 2s"
  10.         sleep(2)
  11.  
  12. def execThread(thread):
  13.     global stop
  14.     if thread.isAlive():
  15.         print "Hilo Ejecutandose"
  16.     else:
  17.         stop = False
  18.         print "Hilo antes o despues de ejecutarse"
  19.         t = threading.Thread(target=run) #(ESTO ES LO QUE FALTO AGREGAR)
  20.         thread.start()
  21.        
  22. t = threading.Thread(target=run) #Aqui creas un hilo
  23. execThread(t)
  24. execThread(t)
  25. stop = True
  26. sleep(5)
  27. execThread(t)

gracias por tomarte el trabajo de codificar para un desconocido!
ahora la unica duda que me queda es:
cuando un hilo termina de ejecutarse, queda algun residuo de el en memoria?? porque si es asi, y estamos en la necesidad de correr muchos hilos (porque no podemos iniciar y cortar, iniciar y cortar uno mismo) la cosa se pone mas ineficiente. o estoy tirando cualquier pavada?
  #6 (permalink)  
Antiguo 08/08/2010, 11:40
Avatar de razpeitia
Moderador
 
Fecha de Ingreso: marzo-2005
Ubicación: Monterrey, México
Mensajes: 7.321
Antigüedad: 19 años, 1 mes
Puntos: 1360
Respuesta: problema con hilos (malditos hilos en python xD)

Para que quieres detener la ejecución de un hilo?

Si necesitas que termine un hilo, antes de que empiecen una serie de hilos puedes sincronizarlos.

Con respecto a lo de la memoria de eso se encarga el gc (Garbage Collector) o recolector de basura así que no tienes que preocuparte por eso.

Pondré algunos ejemplos:
Código Python:
Ver original
  1. ...
  2. #Aqui x nunca es accesado, por lo tanto ese espacio que ocupa en memoria puede
  3. #ser reciclado
  4. x = 12
  5. if y:
  6.     do_something()
  7. else:
  8.     do_something_else()
  9. ...
  10.  
  11. ...
  12. #Aqui x solo es accesado una vez, puede ser candidato a ser reciclado una vez
  13. #ejecutado
  14. x = 12
  15. if (x &#37; y) == 0:
  16.     print "Multiplo"
  17. else:
  18.     print "No multiplo"
  19. ...
  20.  
  21. ...
  22. #Aqui el objeto Foo nunca es acesado, se dice que es basura sintactica
  23. x = Foo()
  24. y = Bar()
  25. x = Qwerty()
  26. ...
  27.  
  28. ...
  29. x = 12
  30. if (x % y) == 0:
  31.     print "Multiplo"
  32. else:
  33.     print "No multiplo"
  34. del x #Aqui liberas el espacio que ocupa x manualmente.
  35. ...
  #7 (permalink)  
Antiguo 08/08/2010, 12:17
 
Fecha de Ingreso: febrero-2010
Mensajes: 10
Antigüedad: 14 años, 2 meses
Puntos: 0
Respuesta: problema con hilos (malditos hilos en python xD)

la idea de iniciar y pausar un hilo varias veces es la siguiente:
yo tengo un hilo principal que maneja una interfaz grafica. En esta hay varios paneles a los cuales se acceden apretando los botones "siguiente" y "anterior" de los paneles (tipico instalador de programas)
el tema es que en uno de los paneles necesito ver si hay algunos dispositivos (como pendrives, cds, dvds, etc) conectados, por lo que necesito un segundo hilo que cada cierto tiempo actualice los dispositivos.
el problema es que el usuario puede ir para atras y volver, con lo cual mataria el hilo y lo volveria a empezar y es aqui donde tuve que postear mi problema ;) que ahora ya esta resuelto.

en cuanto al manejo de memoria tenes razon, al crear otro objeto "hilo" el anterior queda sin referencia, por lo cual es candidato para que se lo lleve el garbage.
muchas gracias por todas las explicaciones razpeitia, me quedo todo muy claro :D
saludos!
  #8 (permalink)  
Antiguo 08/08/2010, 13:58
 
Fecha de Ingreso: junio-2010
Mensajes: 29
Antigüedad: 13 años, 10 meses
Puntos: 0
Respuesta: [Resuelto] problema con hilos (malditos hilos en python xD)

Yo tengo la misma duda, basicamente si haces un porgrama con interfaz grafica, o sin... pero en mi caso tambien es con interfaz grafica y por lo que sea hay una opcion empezar, que se hace con un thread, para liberar al programa principal, y por lo que sea tienes una opcion parar, como se puede hacer para matar el hilo...
  #9 (permalink)  
Antiguo 08/08/2010, 19:52
Avatar de razpeitia
Moderador
 
Fecha de Ingreso: marzo-2005
Ubicación: Monterrey, México
Mensajes: 7.321
Antigüedad: 19 años, 1 mes
Puntos: 1360
Respuesta: [Resuelto] problema con hilos (malditos hilos en python xD)

Lo ideal es terminar cada hilo apropiadamente, esto se puede hacer checado en intervalos regulares el flag "exit" o "salida". Si el flag es verdadero para algún hilo entonces que termine su ejecución apropiadamente.

Para mas información aquí.
  #10 (permalink)  
Antiguo 22/09/2010, 23:17
 
Fecha de Ingreso: septiembre-2008
Mensajes: 4
Antigüedad: 15 años, 6 meses
Puntos: 0
Respuesta: [Resuelto] problema con hilos (malditos hilos en python xD)

El asunto es si el hilo queda trabado en alguna función como raw_input() o socket.recv(),

¿Cómo se podría hacer para matarlos a los threading.Thread's?
  #11 (permalink)  
Antiguo 22/09/2010, 23:38
Avatar de razpeitia
Moderador
 
Fecha de Ingreso: marzo-2005
Ubicación: Monterrey, México
Mensajes: 7.321
Antigüedad: 19 años, 1 mes
Puntos: 1360
Respuesta: [Resuelto] problema con hilos (malditos hilos en python xD)

A que le llamas "trabado"?

Para los sockets para eso hay un timeout (para que no queden esperando infinitamente) y para raw_input no se me ocurre como se puede quedar "trabado" ya que lanza excepciones cuando algo sale mal.
  #12 (permalink)  
Antiguo 23/09/2010, 09:31
AlvaroG
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: [Resuelto] problema con hilos (malditos hilos en python xD)

Python no provee funcionalidad para matar un hilo a voluntad. El hilo debe terminar su método run. Esto es porque cada hilo debe ser capaz de liberar los recursos que tenga y terminar lo que tenga pendiente antes de finalizar.

Si un hilo se te queda colgado esperando algo que nunca llegará, lo que deberías hacer no es intentar matarlo sino reacomodar la tarea que debe hacer, de modo que no se quede colgado.


saludos.
  #13 (permalink)  
Antiguo 23/09/2010, 14:39
 
Fecha de Ingreso: septiembre-2008
Mensajes: 4
Antigüedad: 15 años, 6 meses
Puntos: 0
Respuesta: [Resuelto] problema con hilos (malditos hilos en python xD)

Cita:
Iniciado por AlvaroG Ver Mensaje
Python no provee funcionalidad para matar un hilo a voluntad. El hilo debe terminar su método run. Esto es porque cada hilo debe ser capaz de liberar los recursos que tenga y terminar lo que tenga pendiente antes de finalizar.

Si un hilo se te queda colgado esperando algo que nunca llegará, lo que deberías hacer no es intentar matarlo sino reacomodar la tarea que debe hacer, de modo que no se quede colgado.


saludos.
ok, GRACIAS

Justo había encontrado un artículo que decía que no intentara matar un hilo colgado por un socket bloqueante porque fastidiaría todo.




Cita:
Iniciado por razpeitia Ver Mensaje
A que le llamas "trabado"?

Para los sockets para eso hay un timeout (para que no queden esperando infinitamente) y para raw_input no se me ocurre como se puede quedar "trabado" ya que lanza excepciones cuando algo sale mal.
El hilo se quedaría TRABADO/COLGADO esperando que alguien introduzca algo. Porque, según leí, la aplicación termina cuando el hilo principal y todos los demás hilos se hayan muerto (esto es usando theading).

Si yo metiera un RAW_INPUT en un hilo para que mientras se espera la entrada de datos por teclado se hagan otras cosas, al finalizar el hilo principal me quedaría COLGADO el hilo del RAW_INPUT. Se que con un EXIT(0) lo podría matar, pero mataría todos los hilos a la vez y lo que me intereza es matar solo el del RAW_INPUT.

(Esto es un ejemplo hipotético), igualmente ya me quedó claro que no se pueden matar threading.Threads. Lo pongo por eso de que no se te ocurría como se podían quedar trabados con un raw_input.


Saludos

Última edición por DeMoivre; 23/09/2010 a las 14:56

Etiquetas: hilos
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 07:57.