¿Cómo enfrentar el crecimiento masivo de usuarios en una aplicación?
Cuando creamos una aplicación, el manejo de tareas puede ser sencillo con pocos usuarios. Sin embargo, a medida que la aplicación gana popularidad, la gestión de un número creciente de solicitudes se complica. ¿Cómo podemos solucionar esto? A través de técnicas de paralelismo y concurrencia. Estas técnicas permiten una administración más eficiente de las tareas, especialmente en situaciones donde se requiere procesar múltiples operaciones de forma simultánea.
¿Qué diferencia al procesamiento secuencial del concurrente y el paralelo?
Procesamiento secuencial: Cada tarea se completa por completo antes de iniciar la siguiente.
Concurrencia: Comenzamos fragmentos de diversas tareas, pausándolas y retomándolas de forma alterna.
Paralelismo: Las tareas se ejecutan simultáneamente en diversos núcleos de procesamiento, requiriendo tantos núcleos como tareas en paralelo.
¿Cómo implementar concurrencia usando Python?
En Python, la librería threading nos permite introducir concurrencia a través de hilos. A continuación, se muestra un ejemplo de cómo realizar esto.
import threading
import time
defprocesar_solicitud(request_id):print(f"Procesando solicitud {request_id}") time.sleep(3)print(f"Solicitud {request_id} completada")hilos =[]for i inrange(3): hilo = threading.Thread(target=procesar_solicitud, args=(i,)) hilos.append(hilo) hilo.start()for hilo in hilos: hilo.join()print("Todas las solicitudes completadas")
En este código, se simulan las solicitudes aplicando espera de tres segundos para demostrar el procesamiento concurrente.
¿Cómo aplicar el paralelismo con Python?
Para implementar paralelismo, utilizamos multiprocessing, que permite la ejecución de procesos de manera paralela. Aquí tienes un ejemplo básico para calcular el cuadrado de números de forma simultánea:
import multiprocessing
defcalcular_cuadrado(n):return n * n
if __name__ =="__main__": numeros =[1,2,3,4,5]with multiprocessing.Pool()as pool: resultados = pool.map(calcular_cuadrado, numeros)print(resultados)
El uso del pool.map en el ejemplo asegura que cada número se procese en paralelo, proporcionando resultados inmediatos.
¿Cuándo elegir concurrencia sobre paralelismo?
Concurrencia: Ideal para tareas que involucran entrada/salida de datos, ya que permite dividir y manejar las tareas asíncronamente.
Paralelismo: Recomendado para procesos intensivos de cálculo que requieren potencia de procesamiento y pueden ser ejecutados de manera simultánea.
Estas técnicas no solo optimizan el rendimiento de tu aplicación, sino también mejoran su escalabilidad y eficiencia. Ahora que conoces las bases de la concurrencia y el paralelismo en Python, sigue explorando estas herramientas para dominar el desarrollo de aplicaciones eficientes y avanzadas.
La concurrencia y el paralelismo son conceptos clave en la programación de alto rendimiento y el diseño de aplicaciones modernas, especialmente en entornos donde se necesita manejar múltiples tareas al mismo tiempo para optimizar el uso de recursos. Aunque ambos términos están relacionados, representan enfoques diferentes para ejecutar varias tareas simultáneamente. Vamos a desglosar los conceptos básicos y las diferencias.
### Concurrencia
La **concurrencia** se refiere a la capacidad de un sistema para gestionar múltiples tareas al mismo tiempo, sin necesariamente ejecutarlas simultáneamente. En un entorno concurrente, las tareas pueden progresar en paralelo, aunque no estén ejecutándose al mismo tiempo, ya que el sistema cambia rápidamente entre tareas.
#### Ejemplo de concurrencia
Imagina que estás en una cocina preparando varias recetas: cortas los ingredientes de una receta, luego los de otra, y vas alternando. No completas una receta antes de comenzar con otra, sino que cambias entre ellas para hacer progresos en todas.
- **Multithreading**: Un enfoque común de concurrencia en el que múltiples "hilos" de ejecución se utilizan para dividir las tareas. En Python, se pueden utilizar con la biblioteca threading para tareas I/O intensivas (como la lectura y escritura en archivos o las solicitudes de red), debido a las limitaciones del Global Interpreter Lock (GIL).
El **paralelismo** es la capacidad de ejecutar múltiples tareas al mismo tiempo, aprovechando varios núcleos de CPU. En un entorno verdaderamente paralelo, varias tareas se ejecutan simultáneamente en diferentes núcleos, lo que es ideal para tareas que requieren un uso intensivo de CPU.
#### Ejemplo de paralelismo
Siguiendo el ejemplo de la cocina, en un entorno paralelo, tienes varios chefs en la cocina, y cada uno trabaja en una receta diferente simultáneamente.
- **Multiprocessing**: En Python, la biblioteca multiprocessing permite crear varios procesos independientes que pueden ejecutarse en paralelo, sin las limitaciones del GIL. Esto es útil para tareas que necesitan cálculos intensivos, como el procesamiento de grandes volúmenes de datos.
from multiprocessing import Process
deftarea(nombre):  print(f"Iniciando tarea: {nombre}")proceso1 = Process(target=tarea, args=("Tarea 1",))proceso2 = Process(target=tarea, args=("Tarea 2",))proceso1.start()proceso2.start()proceso1.join()proceso2.join()
### Diferencias clave entre concurrencia y paralelismo
| **Definición** | Habilidad de manejar múltiples tareas al mismo tiempo. | Ejecución simultánea de tareas en diferentes núcleos. |
| **Ejemplo** | threading (conmutación rápida entre tareas). | multiprocessing (tareas ejecutadas en paralelo). |
| **Aplicaciones** | Ideal para tareas I/O intensivas. | Ideal para tareas CPU intensivas. |
### Concurrencia y paralelismo en Python: retos y limitaciones
Python maneja la concurrencia con hilos (threading) y el paralelismo con procesos (multiprocessing). Sin embargo, el **GIL** limita la ejecución de hilos en Python, lo que hace que el uso de multiprocessing sea preferible para tareas intensivas en CPU, mientras que threading es útil para tareas de I/O.
### Alternativas: asyncio para concurrencia asíncrona
Para manejar concurrencia de manera más eficiente, Python también ofrece asyncio, que permite trabajar con tareas asíncronas sin crear múltiples hilos o procesos. Es especialmente útil en aplicaciones de red y permite manejar tareas I/O en paralelo de manera eficiente.
- **Concurrencia**: Capacidad de manejar múltiples tareas a la vez, alternando entre ellas. Ideal para tareas de I/O intensivas.
- **Paralelismo**: Ejecución simultánea de tareas en múltiples núcleos. Ideal para tareas CPU intensivas.
- **asyncio**: Permite manejar tareas asíncronas y concurrentes de manera eficiente sin usar múltiples hilos o procesos.
Cada enfoque tiene sus fortalezas y limitaciones, y la elección depende de la naturaleza de las tareas.
Nice explanation
excelente explicacion
La verdad es que se me hace muy cuesta arriba comprender las clases porque siempre se usan las mismas palabras para nombrar variables, métodos, clases, etc. Aunque tengan una letra mayúscula o una "s" de diferencia el código resulta siendo una repetición constante de la misma palabra (en este caso por ejemplo "thread") y se me hace totalmente incomprensible.
Me da pena porque empecé con mucha ilusión el curso pero a estas alturas se me está haciendo muy frustrante y siento que no estoy asimilando bien las lecciones. Cada vez que veo un video tengo que buscar la misma lección en youtube o preguntar a chatGPT para que me lo explique porque siento que no me he enterado de casi nada...
Muchas gracias por tu aporte.
Creo que este no es un curso para principiantes, si bien se manejan conceptos desde 0 el curso avanza muy rapido y cuesta trabajo seguirlo sino tienes bases previas.
Importante, validado con ChatGPT:
Cuando estemos trabajando con Multiprocessing (Paralelismo) es obligatorio colocar if __name__ == "__main__" en Windows y macOS porque previene errores al crear procesos nuevos.
Cuando usas multiprocessing, Python crea nuevos procesos que importan el archivo actual como módulo. Si no usas ese if, el código que crea procesos se ejecutaría una y otra vez en cada nuevo proceso, causando:
Bucle infinito de creación de procesos
Errores como RuntimeError: freeze_support() must be called... en Windows
Recursión y bloqueo en macOS.
Tanto hablar de hilos , y yo perdi el hilo de la clase ..... =(
Esto es nivel avanzado, siento que deberian sacar un curso para explicar esto en detalle, esta bien que lo mencionen.
Un método estático pertenece a la clase, no a una instancia, y no puede acceder a atributos o métodos de instancia. Se define utilizando el decorador @staticmethod. En cambio, un método de clase recibe la clase como primer argumento (normalmente cls) y puede acceder a atributos y métodos de la clase. Se define con el decorador @classmethod.
Ambos son utilizados para diferentes propósitos, siendo los de clase útiles para manipular la clase en sí y los estáticos para funciones que no requieren acceso a la clase o instancia.
Claps!
Gracias
Cuando corro el Código, se ejecuta sin parar sin darme el resultado. Uso windows 10, tiene alguna idea de por que esto sucede?
me paso igual pero era porque puse el print fuera del if, revisa solo la identacion, ya con eso se corrige, debe de estar dentro del if no fuera, como en python si importa la identacion, si te equivocas pasan cosas raras o manda error, en este caso se ejecuta indefinidamente
¡Claro! El paralelismo en Python se puede lograr utilizando diferentes enfoques dependiendo de tus necesidades. Aquí te explico tres métodos comunes para implementar paralelismo:
1. Usando el módulothreading(Hilos)
El módulo threading permite ejecutar múltiples hilos en paralelo. Sin embargo, debido al Global Interpreter Lock (GIL), no es ideal para tareas intensivas en CPU, pero funciona bien para tareas de E/S (como leer archivos o hacer solicitudes de red).
El threading en Python permite ejecutar múltiples hilos (threads) de ejecución de forma concurrente. Esto es útil en situaciones donde se necesita realizar tareas que pueden ejecutarse de manera independiente, como manejar múltiples solicitudes en una aplicación. Cada hilo puede ejecutar un fragmento de código, permitiendo que las tareas se realicen simultáneamente.
Por ejemplo, al iniciar un hilo, puedes llamar a una función y pasarle argumentos. La función puede ejecutarse mientras otros hilos continúan trabajando. La librería estándar threading facilita la creación y manejo de hilos, y el método join() asegura que el programa espera a que todos los hilos terminen antes de finalizar. Esto optimiza el uso del tiempo en operaciones de entrada y salida (I/O), mejorando la eficiencia en aplicaciones.
hilo.join() es un método en Python que se utiliza para esperar a que un hilo termine su ejecución. Cuando llamas a join() en un hilo, el programa principal se bloquea hasta que ese hilo ha finalizado. Esto es útil para garantizar que todas las tareas en hilos secundarios se completen antes de continuar con la ejecución del programa principal. En el contexto de concurrencia y paralelismo, esto asegura que todos los procesos finalicen correctamente y evita problemas de sincronización.
El método hilo.start() en Python inicia la ejecución de un hilo (thread). Cuando lo llamas, el hilo que se ha creado comienza a ejecutar la función que se ha especificado como su objetivo. Esto permite que el hilo se ejecute de forma concurrente con otros hilos, como se explicó en la clase sobre concurrencia y paralelismo. Recuerda que el hilo se ejecuta en segundo plano, permitiendo que el programa continúe ejecutando otras tareas de manera simultánea.
Hola, para códigos grandes o programas orientados a procesos de automatización, abrir un pool de varios procesos de forma paralela de forma local, consume mucha memoria o recursos físicos de la máquina?
Threading y multiprocessing son dos técnicas de concurrencia en Python.
Threading: Utiliza hilos (threads) para ejecutar tareas en paralelo, compartiendo el mismo espacio de memoria. Es ideal para I/O-bound tasks, donde las tareas esperan por operaciones de entrada/salida. Ejemplo: aplicaciones que manejan múltiples conexiones de red.
Multiprocessing: Crea procesos separados que no comparten memoria, utilizando múltiples núcleos de CPU. Es adecuado para CPU-bound tasks, que requieren mucho procesamiento, como cálculos intensivos.
Ambas técnicas permiten mejorar la eficiencia, pero se eligen según las necesidades específicas del tipo de tarea.
No se recomienda ejecutar paralelismo con multiprocessing en Jupyter Notebooks porque al crear procesos hijos, estos pueden intentar reiniciar el entorno completo, causando bloqueos, recursión infinita o cuelgues. Es mejor usar scripts .py o multiprocessing.dummy con hilos.
este sema segun veo es importante, deberian dedicarle un poco mas de tiempo y explicarlo mejor mas detallado y ver bien como implementarlo tal vez con ejemplos reales, entendi un poco pero tengo mucha curiosidad por este tema!!!