La concurrencia es una técnica que permite que múltiples tareas se ejecuten de manera simultánea, mejorando la eficiencia y el rendimiento de las aplicaciones. En Python, la concurrencia se puede lograr utilizando hilos (threads) y procesos (processes). Este tema cubre los conceptos básicos de hilos y procesos, cómo utilizarlos en Python, y proporciona ejemplos prácticos y ejercicios para reforzar el aprendizaje.
Conceptos Clave
-
Concurrencia vs. Paralelismo:
- Concurrencia: Múltiples tareas progresan simultáneamente.
- Paralelismo: Múltiples tareas se ejecutan exactamente al mismo tiempo, generalmente en múltiples núcleos de CPU.
-
Hilos (Threads):
- Un hilo es la unidad más pequeña de procesamiento que puede ser programada.
- Los hilos comparten el mismo espacio de memoria dentro de un proceso.
-
Procesos (Processes):
- Un proceso es una instancia de un programa en ejecución.
- Los procesos tienen su propio espacio de memoria independiente.
Hilos en Python
Python proporciona el módulo threading
para trabajar con hilos. A continuación, se muestra un ejemplo básico de cómo crear y ejecutar hilos.
Ejemplo: Uso de Hilos
import threading import time def print_numbers(): for i in range(5): print(f"Number: {i}") time.sleep(1) def print_letters(): for letter in 'abcde': print(f"Letter: {letter}") time.sleep(1) # Crear hilos thread1 = threading.Thread(target=print_numbers) thread2 = threading.Thread(target=print_letters) # Iniciar hilos thread1.start() thread2.start() # Esperar a que los hilos terminen thread1.join() thread2.join() print("Hilos completados")
Explicación del Código
- Importación de Módulos: Se importan los módulos
threading
ytime
. - Definición de Funciones: Se definen dos funciones,
print_numbers
yprint_letters
, que imprimen números y letras respectivamente. - Creación de Hilos: Se crean dos hilos,
thread1
ythread2
, asignando las funciones como objetivos. - Inicio de Hilos: Se inician los hilos con
start()
. - Esperar Finalización: Se utiliza
join()
para esperar a que ambos hilos terminen antes de continuar.
Procesos en Python
Para trabajar con procesos, Python proporciona el módulo multiprocessing
. A continuación, se muestra un ejemplo básico de cómo crear y ejecutar procesos.
Ejemplo: Uso de Procesos
import multiprocessing import time def print_numbers(): for i in range(5): print(f"Number: {i}") time.sleep(1) def print_letters(): for letter in 'abcde': print(f"Letter: {letter}") time.sleep(1) # Crear procesos process1 = multiprocessing.Process(target=print_numbers) process2 = multiprocessing.Process(target=print_letters) # Iniciar procesos process1.start() process2.start() # Esperar a que los procesos terminen process1.join() process2.join() print("Procesos completados")
Explicación del Código
- Importación de Módulos: Se importan los módulos
multiprocessing
ytime
. - Definición de Funciones: Se definen dos funciones,
print_numbers
yprint_letters
, que imprimen números y letras respectivamente. - Creación de Procesos: Se crean dos procesos,
process1
yprocess2
, asignando las funciones como objetivos. - Inicio de Procesos: Se inician los procesos con
start()
. - Esperar Finalización: Se utiliza
join()
para esperar a que ambos procesos terminen antes de continuar.
Comparación: Hilos vs. Procesos
Característica | Hilos (Threads) | Procesos (Processes) |
---|---|---|
Espacio de Memoria | Comparten el mismo espacio de memoria | Tienen su propio espacio de memoria |
Creación | Más rápidos y ligeros | Más lentos y pesados |
Comunicación | Más fácil (comparten memoria) | Más difícil (necesitan mecanismos de IPC) |
Seguridad | Menos seguros (problemas de sincronización) | Más seguros (memoria independiente) |
Ejercicio Práctico
Ejercicio 1: Contador Concurrente
Escribe un programa que cree dos hilos. Un hilo debe contar de 1 a 5 y el otro hilo debe contar de 6 a 10. Ambos hilos deben imprimir los números con un retraso de 1 segundo entre cada número.
Solución
import threading import time def count_up_to_5(): for i in range(1, 6): print(f"Count 1-5: {i}") time.sleep(1) def count_up_to_10(): for i in range(6, 11): print(f"Count 6-10: {i}") time.sleep(1) # Crear hilos thread1 = threading.Thread(target=count_up_to_5) thread2 = threading.Thread(target=count_up_to_10) # Iniciar hilos thread1.start() thread2.start() # Esperar a que los hilos terminen thread1.join() thread2.join() print("Contadores completados")
Ejercicio 2: Procesos Concurrentes
Escribe un programa que cree dos procesos. Un proceso debe imprimir "Proceso 1" cinco veces con un retraso de 1 segundo entre cada impresión, y el otro proceso debe imprimir "Proceso 2" cinco veces con el mismo retraso.
Solución
import multiprocessing import time def process_one(): for _ in range(5): print("Proceso 1") time.sleep(1) def process_two(): for _ in range(5): print("Proceso 2") time.sleep(1) # Crear procesos process1 = multiprocessing.Process(target=process_one) process2 = multiprocessing.Process(target=process_two) # Iniciar procesos process1.start() process2.start() # Esperar a que los procesos terminen process1.join() process2.join() print("Procesos completados")
Resumen
En esta sección, hemos cubierto los conceptos básicos de concurrencia utilizando hilos y procesos en Python. Aprendimos cómo crear y manejar hilos y procesos, y discutimos las diferencias clave entre ellos. Además, proporcionamos ejemplos prácticos y ejercicios para reforzar el aprendizaje. La concurrencia es una herramienta poderosa para mejorar el rendimiento de las aplicaciones, y comprender cómo utilizar hilos y procesos es esencial para cualquier programador avanzado en Python.
En el próximo tema, exploraremos los Administradores de Contexto, una característica avanzada de Python que facilita la gestión de recursos como archivos y conexiones de red.
Curso de Programación en Python
Módulo 1: Introducción a Python
- Introducción a Python
- Configuración del Entorno de Desarrollo
- Sintaxis de Python y Tipos de Datos Básicos
- Variables y Constantes
- Entrada y Salida Básica
Módulo 2: Estructuras de Control
- Sentencias Condicionales
- Bucles: for y while
- Herramientas de Control de Flujo
- Comprensiones de Listas
Módulo 3: Funciones y Módulos
- Definición de Funciones
- Argumentos de Función
- Funciones Lambda
- Módulos y Paquetes
- Visión General de la Biblioteca Estándar
Módulo 4: Estructuras de Datos
Módulo 5: Programación Orientada a Objetos
Módulo 6: Manejo de Archivos
- Lectura y Escritura de Archivos
- Trabajo con Archivos CSV
- Manejo de Datos JSON
- Operaciones de Archivos y Directorios
Módulo 7: Manejo de Errores y Excepciones
- Introducción a las Excepciones
- Manejo de Excepciones
- Lanzamiento de Excepciones
- Excepciones Personalizadas
Módulo 8: Temas Avanzados
- Decoradores
- Generadores
- Administradores de Contexto
- Concurrencia: Hilos y Procesos
- Asyncio para Programación Asíncrona
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias con unittest
- Desarrollo Guiado por Pruebas
- Técnicas de Depuración
- Uso de pdb para Depuración
Módulo 10: Desarrollo Web con Python
- Introducción al Desarrollo Web
- Fundamentos del Framework Flask
- Construcción de APIs REST con Flask
- Introducción a Django
- Construcción de Aplicaciones Web con Django
Módulo 11: Ciencia de Datos con Python
- Introducción a la Ciencia de Datos
- NumPy para Computación Numérica
- Pandas para Manipulación de Datos
- Matplotlib para Visualización de Datos
- Introducción al Aprendizaje Automático con scikit-learn