Ir al contenido principal

Guía definitiva: tutorial de threading en Python

Aprende los conceptos básicos de threading y cómo usarlo con la ayuda de Python.
Actualizado 17 sept 2026  · 12 min leer

Explorar con IA

ChatGPTClaudePerplexity

Si acabas de empezar con Python y quieres seguir aprendiendo, haz el curso Introduction to Data Science in Python de DataCamp.

graphic

Introducción

El threading permite que distintas partes de tu proceso se ejecuten de forma concurrente (Fuente: RealPython). Estas partes suelen ser independientes y tienen una unidad de ejecución separada que pertenece al mismo proceso. Un proceso no es más que un programa en ejecución que contiene unidades que pueden ejecutarse en paralelo. Por ejemplo, un navegador web puede ser un proceso; una aplicación que usa varias cámaras a la vez puede ser otro proceso; un videojuego es otro ejemplo de proceso.

Dentro de un proceso aparece el concepto de múltiples hilos, o multithreading, donde varios hilos colaboran para alcanzar un objetivo común. La gran ventaja de usar hilos es que te permite ejecutar el programa en paralelo.

Veamos el concepto de threading con un ejemplo. Imagina una aplicación que cuenta los coches que entran y salen del aparcamiento de un centro comercial. El sistema tiene varias cámaras conectadas a un dispositivo central que monitorizan entradas y salidas. Cada cámara ejecuta un algoritmo para vigilar el flujo de coches y forma parte del mismo proceso o programa. Sin embargo, cada cámara, junto con el algoritmo que ejecuta, podría estar en un hilo independiente. Es más, la lectura de fotogramas de la cámara y la inferencia del algoritmo sobre esos fotogramas podrían ser dos hilos distintos.

Otro ejemplo sería un videojuego en el que el proceso necesita ejecutar tareas en paralelo como los gráficos, la interacción con el usuario y la red (en partidas multijugador) para ser siempre responsivo. Para lograrlo, recurre al multithreading, asignando a cada hilo la responsabilidad de una tarea independiente.

Un hilo tiene su propio flujo de ejecución, lo que significa que en el proceso suceden varias cosas a la vez.

Ten en cuenta que todo proceso tiene al menos un hilo, llamado main thread (hilo principal). Si tu programa no define ningún hilo adicional, al menos contará con el hilo principal, es decir, el propio proceso.

Si observas el diagrama superior, hay un proceso con el hilo principal que contiene variables globales y tres hilos diferentes t1, t2 y t3. Cada hilo tiene sus variables locales y su flujo de ejecución. Los hilos comparten en general los recursos del proceso; es decir, los recursos disponibles para el hilo principal también se comparten con los hilos t1, t2 y t3. Todos los hilos pueden acceder a las variables globales y, además, cuentan con sus variables locales.

Existen distintos tipos de hilos:

  • Hilos de kernel
  • Hilos de usuario
  • Combinación de hilos de kernel y de usuario

Veamos ahora algunas ventajas de usar threading en tu programa:

  • El multithreading puede acelerar la ejecución si dispones de múltiples CPU.

  • También te permite realizar otras tareas mientras se ejecutan operaciones de E/S (I/O) gracias a varios hilos o incluso con el hilo principal más un hilo. Por ejemplo, la lectura de fotogramas de la cámara y la inferencia del algoritmo se gestionarán en hilos diferentes. Así, el algoritmo no tendrá que esperar a que llegue un fotograma y la lectura de fotogramas no tendrá que esperar a que termine la ejecución del algoritmo para leer el siguiente.

  • Los hilos dentro de un mismo proceso pueden compartir la memoria y los recursos del hilo principal.

Retos del threading

  • Recuerda que Python, en su implementación CPython, limita la ejecución a un solo hilo a la vez; por tanto, threading no acelera todas las tareas. La razón principal es el Global Interpreter Lock (GIL).

    Si quieres aprender más sobre el GIL, echa un vistazo a este tutorial.

  • Si buscas acelerar tareas intensivas de CPU, threading puede no ser la mejor solución. En esos casos, suele ser más útil el multiprocesamiento.

  • Para ejecutar un programa con muchos hilos, es necesario cambiar de uno a otro con rapidez; por eso, la planificación (scheduling) es clave en programas con muchos hilos.

  • El uso compartido de recursos también puede ser problemático, ya que todos los hilos comparten la misma memoria y las variables globales. Una operación en un hilo podría provocar un error de memoria en otro, o impedir que otro hilo obtenga memoria para realizar su tarea.

Threading en Python

  • En Python, el módulo de hilos es un módulo integrado llamado threading y puede importarse directamente.

  • Como casi todo en Python se representa como objeto, los hilos también son objetos. Un hilo es capaz de:

    • Almacenar datos,
    • Guardarse en estructuras como diccionarios, listas, sets, etc.
    • Pasarse como parámetro a una función.

  • Un hilo también puede ejecutarse como un proceso.

  • Un hilo en Python puede estar en varios estados, como:

    • Espera (wait),
    • Bloqueado (locked).

Veamos ahora cómo implementar threading en Python.

Módulo thread en Python 3

Ten en cuenta que Python 3 mantiene compatibilidad con el módulo thread de Python 2.7. En Python 3 puede importarse como módulo _thread. Veamos un ejemplo para entender el módulo _thread.

import _thread #thread module imported
import time #time module

Definamos una función llamada thread_delay que recibe dos parámetros: el nombre del hilo y el retardo. Dentro de esta función:

  • Defines un contador que empieza en cero,
  • Luego iteras con un bucle while que se ejecutará tres veces,
  • Dentro del while llamas a time.sleep() para añadir un retardo; esto te ayudará a ver cómo se ejecuta el hilo. El retardo se expresa en segundos,
  • Después incrementas el contador en 1,
  • Para comprobar que el hilo se ejecuta bien, imprimes el nombre del hilo y la hora a la que se ejecuta.
def thread_delay(thread_name, delay):
    count = 0
    while count < 3:
        time.sleep(delay)
        count += 1
        print(thread_name, '-------->', time.time())

Ahora, para ejecutar la función anterior en un hilo, usa el método start_new_thread, que pertenece al módulo _thread.

Veamos la docstring del método start_new_thread.

?_thread.start_new_thread
Threading in Python Tutorial

Pasa la función thread_delay sin paréntesis y dos argumentos: el nombre del hilo y el retardo (para poder visualizar la ejecución, ya que es muy rápida).

_thread.start_new_thread(thread_delay, ('t1', 1))
_thread.start_new_thread(thread_delay, ('t2', 3))
10916



t1 --------> 1588077856.4221454
t1 --------> 1588077857.4418247
t2 --------> 1588077858.422453
t1 --------> 1588077858.4431
t2 --------> 1588077861.4371448
t2 --------> 1588077864.438915

En la salida puedes ver que el hilo t1 empieza a ejecutarse primero. Mientras tanto, t2 espera por su retardo de 3 segundos y, en cuanto termina, se ejecuta. El retardo de t1 es de solo 1 segundo.

Cambiemos ahora el retardo de t2 a 5 segundos, de modo que t2 empiece cuando t1 ya haya terminado, ya que t1 tardará solo 3 segundos en completarse.

_thread.start_new_thread(thread_delay, ('t1', 1))
_thread.start_new_thread(thread_delay, ('t2', 5))
14632



t1 --------> 1588078001.4087512
t1 --------> 1588078002.4272866
t1 --------> 1588078003.432218
t2 --------> 1588078005.4082909
t2 --------> 1588078010.4268317
t2 --------> 1588078015.4283602

Implementar threading con el módulo threading

Use mos el mismo ejemplo de antes, pero esta vez con el módulo threading en lugar de _thread.

import threading
import time
def thread_delay(thread_name, delay):
    count = 0
    while count < 3:
        time.sleep(delay)
        count += 1
        print(thread_name, '-------->', time.time())

Dentro del módulo threading está la clase Thread, similar en espíritu a la función start_new_thread del módulo _thread.

Consultemos la docstring de la clase Thread, que admite varios parámetros como group, target (una función), args, etc.

?threading.Thread
Threading in Python Tutorial

En el constructor de Thread, pasarás la función objetivo thread_delay y los argumentos de esa función.

t1 = threading.Thread(target=thread_delay, args=('t1', 1))
t2 = threading.Thread(target=thread_delay, args=('t2', 3))

En el módulo threading, para ejecutar el hilo utilizas el método start(), encargado de ponerlo en marcha.

?t1.start
Threading in Python Tutorial
t1.start()
t2.start()
t1 --------> 1588081121.7790291
t1 --------> 1588081122.7962046
t2 --------> 1588081123.7789369
t1 --------> 1588081123.7980876
t2 --------> 1588081126.7961557
t2 --------> 1588081129.7995002

También puedes usar el método join, que hace que el programa espere hasta que acaben todos los hilos. Cualquier código después de join se ejecutará solo cuando estos hilos hayan terminado.

?t1.join
Threading in Python Tutorial
t1.start()
t2.start()

t1.join()
t2.join()

print("Thread execution is complete!")
t1 --------> 1588081798.7118263
t1 --------> 1588081799.7231226
t2 --------> 1588081800.7129223
t1 --------> 1588081800.730732
t2 --------> 1588081803.7298765
t2 --------> 1588081806.7309563
Thread execution is complete!

Calculemos ahora el volumen de un cubo y de un cuadrado usando threading; es bastante directo.

def volume_cube(a):
    print ("Volume of Cube:", a*a*a)
def volume_square(a):
    print ("Volume of Square:", a*a)
t1 = threading.Thread(target=volume_cube, args=(2))
t2 = threading.Thread(target=volume_square, args=(3))
t1.start()
t2.start()

t1.join()
t2.join()

print("Thread execution is complete!")
Thread execution is complete!


Exception in thread Thread-9:
Traceback (most recent call last):
  File "C:\Program Files\Anaconda3\lib\threading.py", line 926, in _bootstrap_inner
    self.run()
  File "C:\Program Files\Anaconda3\lib\threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
TypeError: volume_square() argument after * must be an iterable, not int
Exception in thread Thread-8:
Traceback (most recent call last):
  File "C:\Program Files\Anaconda3\lib\threading.py", line 926, in _bootstrap_inner
    self.run()
  File "C:\Program Files\Anaconda3\lib\threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
TypeError: volume_cube() argument after * must be an iterable, not int

¿Cómo? En cuanto ejecutaste start apareció un error. Es porque el parámetro args espera una tupla, y como volume_cube y volume_square solo esperan un parámetro, necesitas poner una coma en args tras indicar el primer argumento de las funciones.

t1 = threading.Thread(target=volume_cube, args=(2,))
t2 = threading.Thread(target=volume_square, args=(3,))
t1.start()
t2.start()

t1.join()
t2.join()

print("Thread execution is complete!")
Volume of Cube: 8
Volume of Square: 9
Thread execution is complete!

Veamos ahora cómo usar threading creando una subclase.

Threading como subclase

En esta sección aprenderás a crear una subclase de la clase Thread, disponible en el módulo threading, y luego crear instancias de hilo t1 y t2 a partir de esa clase.

Usaremos de nuevo la función thread_delay.

class DataCampThread(threading.Thread):
    def __init__(self, name, delay):
        threading.Thread.__init__(self)
        self.name = name
        self.delay = delay


    def run(self):
        print('Starting Thread:', self.name)
        thread_delay(self.name,self.delay)
        print('Execution of Thread:', self.name, 'is complete!')


t1 = DataCampThread('t1', 1)
t2 = DataCampThread('t2', 3)    

t1.start()
t2.start()

t1.join()
t2.join()

print("Thread execution is complete!")
Starting Thread: t1
Starting Thread: t2
t1 --------> 1588089083.4879806
t1 --------> 1588089084.489222
t1 --------> 1588089085.4909666
Execution of Thread: t1 is complete!
t2 --------> 1588089085.4979634
t2 --------> 1588089088.499365
t2 --------> 1588089091.5012596
Execution of Thread: t2 is complete!
Thread execution is complete!

Entendamos el código paso a paso:

  • Definiste una clase DataCampThread y, como argumento de clase, pasaste threading.Thread. Lo haces para crear una subclase del módulo threading. Así puedes usar todos los métodos disponibles en threading.Thread, de forma similar a la herencia.

  • Después definiste el método init de DataCampThread y pasaste el nombre y el retardo. Este init actúa como constructor, de forma análoga a los parámetros que pasaste a threading.Thread, pero aquí para la clase DataCampThread.

  • Luego inicializas el init de la clase base threading.Thread y asignas name y delay.

  • Por último, defines el método run. Recuerda que aquí usaste el método start, que bajo el capó llama a run. Como has heredado de la clase principal, puedes modificar run. Así, cuando llames a start, se reflejarán los cambios que hagas en run.

Conclusión

¡Enhorabuena por completar el tutorial!

Este tutorial ha sido una introducción básica al threading en Python. Sin embargo, es un tema amplio y esencial, y puede que hayan quedado conceptos por explorar. No dudes en investigar otros métodos como active count, current thread, etc.

Si quieres profundizar, consulta la documentación de Python sobre paralelismo basado en hilos.

Si estás empezando con Python y quieres aprender más, haz el curso Introduction to Data Science in Python de DataCamp.

Temas
Python

Cursos de Python

Curso

Introducción a Python

4 h
7M
Domina los fundamentos del análisis de datos con Python en cuatro horas y descubre sus paquetes más usados.
Ver detallesRight Arrow
Iniciar Curso
Ver másRight Arrow
Relacionado

Tutorial

Multiprocesamiento en Python: Guía de hilos y procesos

Aprende a gestionar hilos y procesos con el módulo de multiprocesamiento de Python. Descubre las técnicas clave de la programación paralela. Mejora la eficacia de tu código con ejemplos.
Kurtis Pykes 's photo

Kurtis Pykes

7 min

Tutorial

Tutorial de pandas en Python: La guía definitiva para principiantes

¿Estás preparado para comenzar tu viaje de pandas? Aquí tienes una guía paso a paso sobre cómo empezar.
Vidhi Chugh's photo

Vidhi Chugh

15 min

Tutorial

Tutorial sobre bucles en Python

Un tutorial introductorio completo sobre los bucles en Python. ¡Aprende y practica los bucles while y Bucle for, los bucles anidados, las palabras clave break y continue, la función range y mucho más!
Satyabrata Pal's photo

Satyabrata Pal

15 min

Tutorial

Desarrollo backend con Python: guía completa para principiantes

Esta guía completa te enseña los fundamentos del backend con Python. Aprende conceptos básicos, frameworks y buenas prácticas para empezar a crear aplicaciones web.
Oluseye Jeremiah's photo

Oluseye Jeremiah

15 min

Tutorial

Funciones en Python: cómo llamar y escribir funciones

Descubre cómo escribir funciones en Python reutilizables y eficientes. Domina los parámetros, las sentencias return y temas avanzados como las funciones lambda. Organiza mejor tu código con main() y otras buenas prácticas.
Karlijn Willems's photo

Karlijn Willems

14 min

Tutorial

Tutorial de módulos de Python: Importarlos, escribirlos y utilizarlos

Aprende a crear e importar módulos de Python. ¡Descubre las mejores prácticas, ejemplos y consejos para escribir código Python reutilizable, organizado y eficiente!

Nishant Kumar

8 min

Ver MásVer Más