viernes, 25 de noviembre de 2011

Hilos en Python

Para comenzar, vamos a ver una definición de hilo, que según Wikipedia es la unidad de procesamiento más pequeña que puede ser planificada por un sistema operativo y permite a una aplicación realizar varias tareas a la vez (concurrentemente). Los distintos hilos de ejecución comparten una serie de recursos tales como el espacio de memoria, los archivos abiertos, situación de autenticación, etc. Esta técnica permite simplificar el diseño de una aplicación que debe llevar a cabo distintas funciones simultáneamente.

En el artículo que nos ocupa, vamos a analizar cómo implementar y utilizar los hilos en Python. El módulo que vamos a utilizar es el módulo threading por lo que habrá que impotarlo al comienzo de nuestros programas con la línea:
import threading
Una vez importado esto, el hilo de ejecución que queramos crear deberá heredar de la clase Thread. En esta clase debemos definir el método run, que contendrá el código que queremos que ejecute nuestro hilo. Además, podemos crear nuestro propio constructor, que ha de tener una llamada al conductor de la clase de la que hereda:

class MiThread(threading.Thread):
def __init__(self, num):
threading.Thread.__init__(self)
self.num = num

def run(self):
print "Soy el hilo ", self.num

Para ejecutar el hilo, tenemos que crear una instancia del mismo y ejecutar el método start(). Por ejemplo, en el siguiente bucle vamos a lanzar diez hilos:
for i in range(0,10):
t = MiThread(i)
t.start()
t.join()
Si queremos que el hilo principal se quede esperando a que un hilo concreto termine su ejecución utilizamos el método join() de este hilo. En el caso anterior, los hilos no se ejecutarían simultáneamente, ya que el programa principal se quedaría en el join esperando a que terminara la ejecución de cada uno de ellos antes de pasar a la siguiente iteración del bucle. Un ejemplo de join que se vio en clase es el siguiente:

num1 = 1000
num2 = 500
thr1 = MiHilo( num1, "Hilo 1" )
thr2 = MiHilo( num2, "Hilo 2" )
thr2.start()
print "Lanzado hilo 2"
thr1.start()
print "Lanzado hilo 1"
thr1.join()
print "Terminó hilo 1"
thr2.join()
print "Terminó hilo 2"

En este caso, thr2 y thr1 se lanzan en ese orden pero el hilo principal se queda esperando a que termine thr1 usando su join y después a que termine thr2. En el caso de que thr2 termine antes que thr1 estaríamos perdiendo cierto tiempo de ejecución esperando la terminación de thr2. Para evitar esta situación existe en la librería threading el método activeCount() que nos devuelve el número de hilos activos incluyendo al principal. De ese modo, podríamos hacer que en el ejemplo anterior se esperara a la finalización de los dos hilos de la siguiente manera:
thr2.start()
thr1.start()
while threading.activeCount()>1:
pass
print "Fin."
Así, mientras que hubiera más de un hilo vivo, se ejecutaría la orden pass (que no hace nada) y no saldríamos del bucle hasta que solamente estuviera vivo el hilo principal.

Otras funciones interesantes de los hilos
  • Para comprobar si un hilo está en ejecución se puede utilizar el método isAlive().
  • Para asignar o consultar el nombre de un hilo se pueden usar setName() y getName().
  • Para obtener una lista de los objetos Thread en ejecución, podemos llamar a threading.enumerate()

Enlaces utilizados:



No hay comentarios:

Publicar un comentario