Curso Python. Volumen XX: Hilos (Threading). Parte I

Escrito por Javier Ceballos Fernández
Programación

Bienvenidos un día más al curso de Python. En este capítulo vamos a hablar de la ejecución de hilos, para poder realizar tareas simultáneas en nuestras aplicaciones. Se trata de un recurso muy utilizado en programación para agilizar la ejecución de las tareas. Así que pongámonos manos a la obra.

Como os he comentado es una técnica de programación permite que una aplicación ejecute simultáneamente varias operaciones en el mismo espacio de proceso, en inglés se denomina “Threading”. A cada flujo de ejecución que se origina durante el procesamiento se le denomina hilo o subproceso, pudiendo realizar o no una misma tarea. En Python, el módulo “threading” hace posible la programación con hilos.

Existen multitud de situaciones en las que la utilización de hilos puede resultar interesante, por ejemplo: una aplicación que realice varias descargas de ficheros en paralelo, una aplicación que pueda abrir o guardar un documento de un gran tamaño mientras se está editando otro, aplicaciones que permitan lanzar varias operaciones de búsqueda al mismo tiempo, aplicaciones que prueben el funcionamiento de un conjunto de sistemas simultáneamente, etc. Como podéis comprobar hay multitud de situaciones en las que se pueden aplicar hilos.

Ejecutar varios hilos o subprocesos es similar a ejecutar varios programas diferentes al mismo tiempo, pero con algunas ventajas añadidas:

  • Los hilos en ejecución de un proceso comparten el mismo espacio de datos que el hilo principal y pueden, por tanto, tener acceso a la misma información o comunicarse entre sí más fácilmente que si estuvieran en procesos separados.
  • Ejecutar un proceso de varios hilos suele requerir menos recursos de memoria que ejecutar lo equivalente en procesos separados.

Permite simplificar el diseño de las aplicaciones que necesitan ejecutar varias operaciones de manera concurrente.

Para cada hilo de un proceso existe un puntero que realiza el seguimiento de las instrucciones que se ejecutan en cada momento. Además, la ejecución de un hilo se puede detener temporalmente o de manera indefinida. En general, un proceso sigue en ejecución cuando al menos uno de sus hilos permanece activo, es decir, cuando el último hilo concluye su cometido, termina el proceso, liberándose en ese momento todos los recursos utilizados.

Objetos Thread: los hilos

En Python un objeto “Thread” representa una determinada operación que se ejecuta como un subproceso independiente, es decir, es la representación de un hilo. Se pueden definir de dos formas los hilos:

  • La primera consiste en pasar al método constructor un objeto invocable, como una función, que es llamada cuando se inicia la ejecución del hilo.
  • La segunda sería creando una subclase de “Thread” en la que se reescribe el método “run()” y/o el constructor “__init__()”.

En el siguiente ejemplo vamos a crear dos hilos que llaman a la función contar. En dicha función se utiliza una variable contadora para contar hasta cien. Los objetos “Thread” (los hilos) utilizan el argumento “target” para establecer el nombre de la función a la que hay que llamar. Una vez que los hilos se hayan creado se iniciarán con el método “start()”. A todos los hilos se les asigna, automáticamente, un nombre en el momento de la creación que se puede conocer con el método “getName()” y, también, un identificador único (en el momento que son iniciados) que se puede obtener accediendo al valor del atributo “ident”:

import threading

def contar():
    '''Contar hasta cien'''
    contador = 0
    while contador<100:
        contador+=1
        print('Hilo:',threading.current_thread().getName(),
             'con identificador:',threading.current_thread().ident,
             'Contador:', contador)

hilo1 = threading.Thread(target=contar)
hilo2 = threading.Thread(target=contar)
hilo1.start()
hilo2.start()

A continuación, una vamos a realizar una mejora al código del ejemplo anterior ya que ahora vamos a utilizar la constante “NUM_HILOS” para establecer el número de hilos que han de iniciarse. Los hilos se crean e inician implementando un bucle basado en “range()”. En este caso el nombre de cada hilo se construye con el valor de la variable “num_hilo” que es asignado al atributo “name”. Existe otra posibilidad de asignar un nombre a un hilo con el método “hilo.setName(nombre);” y de acceder a su nombre mediante “hilo.name”:

import threading

def contar():
    contador = 0
    while contador<100:
        contador+=1
        print('Hilo:',threading.current_thread().getName(),
              'con identificador:',threading.current_thread().ident,
              'Contador:', contador)

NUM_HILOS = 3

for num_hilo in range(NUM_HILOS):
    hilo = threading.Thread(name='hilo%s' %num_hilo,
            target=contar)
    hilo.start()

Hilos con argumentos

Para ayudarnos a que los programas que utilicen hilos tengan un mejor comportamiento tenemos la posibilidad de enviar valores a los hilos para que los puedan utilizar. Por este motivo existen los argumentos “args” y “kwargs” en el constructor.

En el ejemplo que os presentamos a continuación se utilizan estos argumentos para pasar una variable con el número de hilo que se ejecuta en un momento dado y un diccionario con tres valores que ajustan el funcionamiento del contador en todos los hilos:

import threading
def contar(num_hilo, **datos):
    contador = datos['inicio']
    incremento = datos['incremento']
    limite = datos['limite']
    while contador<=limite:
        print('hilo:', num_hilo, 'contador:', contador)
        contador+=incremento 

for num_hilo in range(3): 
    hilo = threading.Thread(target=contar, args=(num_hilo,)
           ,kwargs={'inicio':0, 'incremento':1,'limite':10}) 
    hilo.start()

Aquí lo dejamos por hoy, para que podáis ir asimilando los nuevos conceptos que os hemos explicado, os invitamos como siempre a que vayáis probando todo lo aprendido hasta el momento.

En el próximo capítulo seguiremos explicando cosas nuevas sobre la ejecución de hilos dentro de una aplicación. Y para todos los que se acaban de incorporar indicarles que tenemos un índice con todos los capítulos del curso, ya que nunca es tarde para empezar.

Fuente > Python para impacientes


Últimos análisis

Valoración RZ
8
Valoración RZ
9
Valoración RZ
9
Valoración RZ
10
Valoración RZ
9
Valoración RZ
10
Valoración RZ
7
Valoración RZ
9
Valoración RZ
10