Sincronía y Concurrencia en Python: Teoría y Práctica
Resumen
Combinar asincronía y concurrencia en un mismo proyecto es una de las estrategias más potentes para construir sistemas eficientes en Python. En este recorrido práctico se construye un sistema de gestión de pedidos que verifica inventario, calcula costos y procesa pagos, utilizando asyncio y multiprocessing de forma conjunta.
¿Cuál es la diferencia entre concurrencia y asincronía en Python?
Aunque suenan parecido, cada concepto resuelve problemas distintos. La concurrencia ejecuta tareas de manera intercalada y cuenta con las librerías threading y multiprocessing; esta última enfocada específicamente en paralelismo para tareas con uso intensivo de CPU [0:20]. La asincronía, en cambio, permite pausar una tarea para dar paso a otra y se apoya en la librería asyncio, ideal para operaciones de entrada y salida de datos (I/O bound) [0:30].
La concurrencia es útil cuando el CPU necesita mucho tiempo de procesamiento.
La asincronía brilla en tareas que dependen de respuestas externas como bases de datos o servicios de pago.
Ambas pueden combinarse en un mismo proyecto para cubrir escenarios distintos.
¿Cómo se diseña el sistema de gestión de pedidos?
El ejercicio plantea un escenario real: un sistema que debe verificar inventario, calcular el costo total y procesar pagos para múltiples órdenes de forma simultánea [1:00].
¿Cómo funciona la verificación de inventario con asyncio?
Se crea una función asíncrona llamada check_inventory que recibe un item y simula la consulta a una base de datos [1:50]. Dentro de ella se usa await asyncio.sleep() con un tiempo aleatorio generado por random.randint(3, 6) para representar la latencia del servicio. Al finalizar, retorna un valor aleatorio entre True y False mediante random.choice(), simulando la disponibilidad del producto [2:40].
python
async def check_inventory(item):
print(f"Verificando inventario para {item}...")
await asyncio.sleep(random.randint(3, 6))
print(f"Inventario verificado para {item}")
return random.choice([True, False])
¿Cómo se procesa el pago de forma asíncrona?
Otra función asíncrona llamada process_payment recibe un order_id y simula la comunicación con un servicio de pago externo [3:10]. También emplea await asyncio.sleep() para pausar la ejecución y liberar el event loop. Cuando termina, retorna True indicando que el pago fue exitoso.
python
async def process_payment(order_id):
print(f"Procesando pago para la orden {order_id}...")
await asyncio.sleep(random.randint(3, 6))
print(f"Pago procesado para la orden {order_id}")
return True
¿Por qué el cálculo del costo total usa multiprocessing?
La función calculate_total es síncrona porque simula un cálculo pesado de CPU [4:30]. Usa time.sleep(5) para representar ese procesamiento intensivo y calcula la suma de precios iterando sobre cada artículo.
python
def calculate_total(items):
print(f"Calculando costo total para {len(items)} artículos...")
time.sleep(5)
total = sum(item["precio"] for item in items)
print(f"Costo total calculado: {total}")
return total
¿Cómo se combinan asincronía y multiprocesamiento en la función principal?
La función process_order es asíncrona y orquesta todo el flujo [5:50]. Primero verifica el inventario de cada artículo usando asyncio.gather(), un método que lanza múltiples corrutinas de forma concurrente y espera a que todas terminen [6:50]. Si algún producto no está disponible, la orden se cancela.
Para el cálculo del total se crea un pool de procesos con multiprocessing.Pool, enviando la función calculate_total mediante pool.apply() y los artículos como tupla iterable [7:40]. Finalmente, el pago se procesa de forma asíncrona con await.
python
async def process_order(order_id, items):
checks = [check_inventory(item["nombre"]) for item in items]
results = await asyncio.gather(*checks)
if not all(results):
print(f"Orden {order_id} cancelada: producto no disponible")
return
with multiprocessing.Pool() as pool:
total = pool.apply(calculate_total, (items,))
payment = await process_payment(order_id)
if payment:
print(f"Orden {order_id} completada. Total: {total}")
En la función main se definen tres órdenes, cada una con un order_id y una lista de artículos con nombre y precio [9:20]. Se construye una lista de tareas iterando sobre las órdenes y se ejecutan con asyncio.gather(*tasks). Todo arranca con el event loop mediante asyncio.run(main()) [10:50].
Al ejecutar el programa, las tres órdenes se procesan de forma simultánea. Los tiempos aleatorios hacen que cada ejecución produzca resultados diferentes: algunas órdenes se completan y otras se cancelan dependiendo del random.choice en la verificación de inventario [11:30].
Si ya estás experimentando con estos patrones, comparte cómo los aplicarías en tus propios proyectos y deja tus dudas en los comentarios.
En este código solo agregue una función logger que ayuda a visualizar mejor cada proceso por orden.
import asyncio, multiprocessing, time, random
fromenumimportEnumclassStatus(Enum):START='START 🔘'PENDING='PENDING 🚧'CANCELED='CANCELED ❌'FINISHED='FINISHED 🎉'def logger(order_id: int,status:Status,message: str):print(f'[order_id: {order_id}], status: {status.value}, message: {message}')async def check_inventory(order_id, item):logger(order_id,Status.START, f'Verificado Inventario para item {item}')await asyncio.sleep(random.randint(3,6))logger(order_id,Status.START, f'Inventario verificado para {item}')print("------------------------------------------------------------------------------------") #simulando disponibilidad
return[item, random.choice([True,False])]async def process_payment(order_id):logger(order_id,Status.PENDING,'Enviando a procesar pago')await asyncio.sleep(random.randint(2,3))logger(order_id,Status.FINISHED,'Pago procesado correctamente')print("------------------------------------------------------------------------------------")returnTrue#Funcion intensiva en CPU para calcular el costo total del pedido
def calculate_total(order_id, items):logger(order_id,Status.START, f'Calculado el costo total para {len(items)} articulos..') time.sleep(5) total =sum(item['price']for item in items)logger(order_id,Status.START, f'Costo total de la orden es: {total}')print("------------------------------------------------------------------------------------")return total
async def process_order(order_id, items):print(f'[order_id: {order_id}], status: START, message: iniciando proceso')logger(order_id,Status.START,'Iniciando proceso') inventory_checks =[check_inventory(order_id, item['name'])for item in items] inventory_result =await asyncio.gather(*inventory_checks) result =[item for item in inventory_result if item[1]==False]ifresult:logger(order_id,Status.CANCELED, f'Productos {result[0][0]} no disponibles')returnwith multiprocessing.Pool()aspool: total = pool.apply(calculate_total,(order_id, items,))
#procesar pago
payment_result =awaitprocess_payment(order_id)ifpayment_result:logger(order_id,Status.FINISHED, f'Procesado correctamente total {total}')else:logger(order_id,Status.CANCELED, f'El pago no puedo ser completado')print("------------------------------------------------------------------------------------")async def main(): orders =[{'order_id':1,'items':[{'name':'Laptop','price':1000},{'name':'Mouse','price':50}]},{'order_id':2,'items':[{'name':'Teclado','price':80},{'name':'Monitor','price':300}]},{'order_id':3,'items':[{'name':'Smartphone','price':700},{'name':'Funda','price':20}]}] #Procesar múltiples órdenes concurrentemente
tasks =[process_order(order['order_id'], order['items'])for order in orders]await asyncio.gather(*tasks)
## creación de event loop
if __name__ =='__main__': asyncio.run(main())
Como no quedaron claros los conceptos explicados en las últimas clases, decidí hacer la siguiente nota con ayuda de IA.
Ejecución Secuencial vs. Concurrencia
1. Ejecución Secuencial
Las tareas se ejecutan una tras otra, sin superposición ni interrupciones.
Ejemplo: Un programa lee un archivo, procesa su contenido y escribe el resultado de forma secuencial. Cada paso espera a que el anterior termine antes de comenzar.
Concepto Erróneo: La ejecución secuencial es siempre ineficiente. En realidad, para tareas simples o dependientes del cómputo, puede ser perfectamente adecuada.
2. Concurrencia
La concurrencia es la capacidad de gestionar múltiples tareas intercalando su ejecución. Esto no significa necesariamente que las tareas se ejecuten al mismo tiempo; pueden alternarse.
La concurrencia puede lograrse en un procesador de un solo núcleo dividiendo el tiempo entre las tareas o en sistemas multicore ejecutando hilos o procesos concurrentemente.
Los núcleos lógicos (habilitados por tecnologías como Hyper-Threading) permiten que un único núcleo físico ejecute múltiples hilos concurrentemente al utilizar recursos inactivos.
Concepto Erróneo: La concurrencia siempre significa que las tareas se ejecutan al mismo tiempo. Se trata de la gestión de tareas, no de la ejecución simultánea.
3. Asincronismo
La programación asíncrona permite que las tareas continúen sin esperar a que otras terminen. Se utiliza comúnmente para operaciones dependientes de E/S donde, de lo contrario, la CPU permanecería inactiva.
Opera principalmente en un solo hilo utilizando un bucle de eventos para gestionar operaciones no bloqueantes (por ejemplo, en asyncio de Python o JavaScript).
Concepto Erróneo: El asincronismo siempre involucra múltiples hilos. Aunque los hilos pueden mejorar el rendimiento asíncrono, no son un requisito.
Nota al margen: ¿Qué es un bucle de eventos? Un bucle de eventos es un constructo de programación que espera y distribuye eventos o mensajes. En la programación asíncrona, gestiona tareas y callbacks de manera no bloqueante.
4. Multitarea
La multitarea implica gestionar múltiples hilos o procesos, intercalando su ejecución. En procesadores de un solo núcleo, esto se logra cambiando rápidamente entre tareas (división del tiempo).
En procesadores multicore, los hilos pueden ejecutarse en paralelo en diferentes núcleos físicos o lógicos.
Concepto Erróneo: La multitarea siempre mejora el rendimiento. Cambiar entre tareas conlleva una sobrecarga, por lo que una multitarea mal diseñada puede ralentizar la ejecución.
5. Paralelismo
El paralelismo implica ejecutar múltiples tareas o hilos simultáneamente en múltiples núcleos físicos.
Ideal para tareas dependientes del cómputo como simulaciones, procesamiento de datos o aprendizaje automático.
Concepto Erróneo: El paralelismo siempre es mejor que la concurrencia. Algunas cargas de trabajo se benefician más de una intercalación eficiente de tareas que de la verdadera ejecución paralela.
Nota al margen: Núcleos físicos vs. núcleos lógicos* Un núcleo físico es un núcleo de hardware real en un procesador.
Un núcleo lógico (vía Hyper-Threading) permite que un núcleo físico maneje múltiples hilos utilizando recursos inactivos dentro del núcleo.
Tabla Resumen: Tipos de Concurrencia
|Tipo|Descripción|Casos de Uso|Diferencias|Similitudes|
|---|---|---|---|---|---|
**|Asincronismo|**Monohilo, no bloqueante, utiliza bucles de eventos para manejar tareas.Tareas dependientes de E/S como archivos/red.|No requiere múltiples hilos; se basa en callbacks/promesas y bucles de eventos.|Tanto el asincronismo como la multitarea permiten manejar múltiples tareas eficientemente.|
|**Multitarea|**Gestiona múltiples tareas intercalando (división del tiempo) o ejecutándolas en paralelo.Ejecutar múltiples aplicaciones, capacidad de respuesta de GUI.|Puede implicar división del tiempo en procesadores de un solo núcleo o ejecución paralela en multicore.|Tanto la multitarea como el paralelismo pueden usar hilos o procesos para la concurrencia.|
|**Paralelismo|**Ejecuta múltiples tareas simultáneamente en múltiples núcleos. Tareas dependientes del cómputo como simulaciones, modelos de ML. |Requiere múltiples núcleos; logra verdadera ejecución simultánea. |Tanto el paralelismo como la multitarea manejan múltiples tareas y pueden beneficiarse de sistemas multicore.|
Explicación Gráfica
Aquí hay una representación visual de los conceptos:
# Tareas ejecutadas una tras otra
tarea("Tarea 1", 2)
tarea("Tarea 2", 2)
tarea("Tarea 3", 2)
2. Concurrencia (Asyncio)
import time
def tarea(nombre, duracion):print(f"Iniciando {nombre}") time.sleep(duracion)print(f"Finalizado {nombre}")# Tareas ejecutadas una tras otra
tarea("Tarea 1",2)tarea("Tarea 2",2)tarea("Tarea 3",2)
3. Multitarea (Threading)
import threading
import time
def tarea(nombre, duracion):print(f"Iniciando {nombre}") time.sleep(duracion)print(f"Finalizado {nombre}")hilos =[]# Crear hilos para cada tarea
for i inrange(1,4): hilo = threading.Thread(target=tarea, args=(f"Tarea {i}",2)) hilos.append(hilo) hilo.start()# Esperar a que todos los hilos terminen
for hilo inhilos: hilo.join()
4. Paralelismo (Multiprocessing)
import multiprocessing
import time
def tarea(nombre, duracion):print(f"Iniciando {nombre}") time.sleep(duracion)print(f"Finalizado {nombre}")if __name__ =="__main__": procesos =[] # Crear procesos para cada tarea
for i inrange(1,4): proceso = multiprocessing.Process(target=tarea, args=(f"Tarea {i}",2)) procesos.append(proceso) proceso.start() # Esperar a que todos los procesos terminen
for proceso inprocesos: proceso.join()
Resumen
Secuencial: Simple pero puede ser ineficiente para cargas de trabajo dependientes de E/S.
Asincronismo: Eficiente para tareas dependientes de E/S, se basa en bucles de eventos.
Multitarea: Intercala tareas, adecuada para cargas que toler
Muchas gracias por tu aporte
Muchas gracias por tomarte tu tiempo de este resumen.
No entiendo de qué nos sirve una clase de 23 minutos copiando un código de memoria o leyendo un guion en el que la profesora solo comenta lo que esta copiando para no subir una video sin audio.
A mi en particular no me importa si copias y pegas el codigo directamente, como programador gracias a la experiencia que tengo en estos meses escribiendo y escribiendo codigo me he dado cuenta que el escribir codigo per se es lo mas irrelevante y sencillo de la tarea de programar. A mi parecer una buena clase habría sido plantear un problema y de ahi desarrollar la logica de qué quieres hacer, cómo y el qué le vas a indicar a python. ¿Qué excepciones pueden ocurrir? ¿Cómo debería tratarlas? ¿Termino la ejecucion o hago un bucle hasta que un valor adecuado sea introducido?
Por qué uso este metodo o solucion en vez de otro, cuál es el pensamiento detrás. Yo no pido una clase de una hora dando y pensando en cada caso exhaustivamente. pero sí una clase en la que solucionas un problema enseñando la logica que hay detras, como si no escribes una linea de codigo. Lo mas importante es enseñar esa logica, qué es cada cosa que usas. No simplemente darla como algo que existe por derecho divino y que se usa aca sin preguntarte nada.
"No enseñamos cosas básicas, enseñamos cosas fundamentales", dijo Freddy en la PlatziConf. Pues el curso de python con 63 clases hasta la clase 58, mucho derecho divino pocos fundamentos.
Totalmente de acuerdo mi hermano, yo solo estoy empezando en este mundo pero con la herramientas actuales como dices, lo de menos es escribir código, la lógica de lo que hacemos y el por que me parece algo fundamental, ya entiendo por que muchos programadores recomienda otra plataforma para aprender.
muy bien
Gracias por tu aporte
esta clase parece que solo esta copiando codigo hecho de antemano. si uno quisiera hacerlo normalmente iniciaría por el main para luego ir creando las funciones más específicas
Estoy de acuerdo, cuando hacen clases muy extensas no permite captar la idea principal ya que es mucha información.
Yo lo que hice fue preguntarle a geminis que me explique cada elemento con ejemplos práticos y luego un ejemplo con todo los elementos.
Aun así este tema es avanzando deberia explicarlo en un curso a parte.
Entiendo tu punto. Sin embargo, lo hermoso de la programación —al menos para algunos— es que permite construir el código desde nuestra propia lógica. En este caso, seguimos la lógica de la profesora que nos guía a través del proceso.
Este código está preparado: primero, porque ella seguramente ya lo ha implementado muchas veces con productos reales; y segundo, porque necesitan que el video sea breve y directo, con la información justa para los estudiantes.
Pero tú y yo sabemos que, detrás de cada solución funcional, hay cientos de errores previos. Como en las películas, no se muestran los intentos fallidos, solo el resultado final.
Lo valioso de que no nos muestren los errores —o de enfrentarnos a ellos nosotros mismos— es que así experimentamos una situación más cercana al mundo laboral real. Aprendemos a entender cómo "piensa" la máquina para identificar por qué no nos da el resultado esperado. Ese es el verdadero aprendizaje.
¿Cuál es la principal diferencia entre la concurrencia y el asincronismo en Python?
En la concurrencia varias tareas parecen ejecutarse al mismo tiempo, pero no necesariamente lo hacen en paralelo. Mientras que el asincronismo las tareas se suspenden y reanudan explícitamente cuando esperan algo, es decir, que en la concurrencia las tareas se dividen entre hilos o procesos y en el asincronismo las tareas cooperan cediendo el control.
Estas clases en donde solo se recrea el código sin mayor explicación, crean frustración. Sería excelente que se tomaran el tiempo de enfocarse un poco más en la lógica atrás de la construcción del código y que los ejemplos de uso sean más claros.
Es totalmente entendible que las clases se deben complementar con recursos adicionales, pero después de ver algo como esto solo te dan ganas de cerrar la PC.
Pero bueno! Hay que sobreponerse a la incomodidad que esto crea, dar feedback, y seguir aprendiendo.
Hay un error en el código, cuando una orden lo puede ser procesada debes parar la ejecución, se siguió ejecutando y dando la opción de pago de algo que ya se verifico que no había. Esto la verdad estuvo muy mal explicado, no dijiste la razón de porque aplicaste uno u otro método en cada función y paso, solo te dedicaste a comentar un código, más atención a la explicación del porqué y para que de una función...
En mi trayecto estudiando, me he dado cuenta de que llegar a tu propia lógica es lo que realmente distingue a un ingeniero o a un verdadero desarrollador. Un desarrollador puede hacer que algo funcione, pero un ingeniero se pregunta por qué funciona, cuándo usarlo y cuál es la mejor solución.
Creo que, como curso para enseñar Python, está bien. Pero si también nos enseñaran a hacernos preguntas sobre los fundamentos y a usarlos en el momento correcto, avanzaríamos no solo como programadores, sino como profesionales capaces de tomar decisiones técnicas bien fundamentadas, sin embargo, creo que para eso esta la universidad o ser muy buen autodidacta.
Realice el ejemplo de la clase, lo único que modifique en código es que cuando no hay disponible un item, la orden no realice los demás procesos (calcular total y procesar orden) y muestre que ocurrió un error.
con este ejemplo de clase se ve mejor los métodos asíncronos y la concurrencia, pero para entenderlo un poquito mas (aun no me queda 100% claro del todo) hice un grafico con esto me ayudo, lo comparto también por si a alguien le sirve.
Y el código tambien
import asyncio
import time
import random
import multiprocessing
#función asincrona para veridicar el inventarioasyncdefcheck_inventory(item):try:# print("\n___________________________________________________________")print(f"verificando inventario para {item} ...")await asyncio.sleep(random.randint(3,6))print(f"inventario VERIFICADO para {item}")# print("___________________________________________________________")#simular disponibilidad del productoreturn random.choice([True,False,True,True])except Exception as ex:print(ex)#función para procesar el pagoasyncdefprocess_payment(order_id):try:# print("\n___________________________________________________________")print(f"Procesando pago para la orden [{order_id}] ...")#simular el tiempo de espera del servicio de pagoawait asyncio.sleep(random.randint(3,6))print(f"Pago procesado para la orden [{order_id}]")# print("___________________________________________________________")returnTrueexcept Exception as ex:print(ex)#Funcion intensiva en CPU para calcular el costo total del pedidodefcalculate_total(items):try:# print("\n___________________________________________________________")print(f"Calculando costo total para {len(items)} articulos ...") time.sleep(5) total =sum(item['price']for item in items)print(f"Costo total calculado: {total}")# print("___________________________________________________________")return total
except Exception as ex:print(ex)asyncdefprocess_order(order_id, items):try: payment_result =False# print("\n___________________________________________________________")print(f"Iniciando el procesamiento de la orden [{order_id}] ...")#Verificar el inventario para cada articulo inventory_check =[check_inventory(item['name'])for item in items]#este crea una lista de funciones a ejecutar inventory_results =await asyncio.gather(*inventory_check)#este indica a asyncio la lista a ejecutar asincronamenteprint(f"fin check_inventory orden [{order_id}]")ifnotall(inventory_results):print(f"Orden [{order_id}] cancelada: Producto no está disponible")else:with multiprocessing.Pool()as pool: total = pool.apply(calculate_total,(items,))#se ejecuta el proceso hasta que termine#Procesar el pago payment_result =await process_payment(order_id)if payment_result:print(f"\n🎉 Orden [{order_id}] completada con éxito. Total: {total}\n")else:# raise Exception(f"\n❌ Error al procesar el pago de la orden [{order_id}]\n")print(f"\n❌ Error al procesar el pago de la orden [{order_id}]\n")# print("___________________________________________________________")return total
except Exception as ex:print(ex)asyncdefmain():try: orders =[{'order_id':1,'items':[{'name':'Laptop','price':1000},{'name':'Mouse','price':50},{'name':'Smartphone','price':700}]},{'order_id':2,'items':[{'name':'Teclado','price':80},{'name':'Monitor','price':300}]},{'order_id':3,'items':[{'name':'Smartphone','price':700},{'name':'Funda','price':20}]}]#Procesar múltiples órdenes concurrentemente tasks =[process_order(order['order_id'], order['items'])for order in orders]await asyncio.gather(*tasks)except Exception as ex:print(ex)#creamos el event loopif __name__ =='__main__': asyncio.run(main())
En un sistema de gestión de pedidos, es posible que los cálculos de precios sigan realizándose incluso después de que un pedido ha sido marcado como cancelado debido a procesos asíncronos o de concurrencia. Es común que las operaciones no se detengan inmediatamente, especialmente si hay procesos en segundo plano que aún están ejecutándose. Esto puede dar la impresión de que los cálculos continúan a pesar de la cancelación, lo que podría ser un área a revisar en cuanto a la lógica de negocio y el manejo de estados en el sistema.
siento que este curso deberia haber terminado hace 10 clases y estas clases para aca debrian estar mejor explicadas porque es algomuy importante pero solo los usan no explican o formas de uso!!! estoy algo confundido y eso que he buscado otros videos que me complementen
Al principio este modulo puede ser complicado, pero es muy util para efecto de simular en back todo un día de trabajo de un negocio y como impactar una base de datos...wao, me volo la cabeza, los escenarios que se pueden montar simulados.....podre de mis CPUs....jajaja
📋 Esquema: Flujo de ejecución deprepararEmpanadas
1. Inicio
Se llama prepararEmpanadas(receta)
2. Bloquetry
Intenta ejecutar el proceso completo
📦 Paso 1: await prepararMasa(receta.masa)
Mezclar harina, agua, sal y colorante
Reposar la masa
🍲 Paso 2: await prepararRelleno(receta.relleno)
Sofreír carne, cebolla, ajo, comino, papa rallada
Cocinar hasta que el relleno espese
🔄 Paso 3: await armarEmpanadas(masa, relleno)
Hacer discos de masa
Rellenar y sellar con los dedos
🔥 Paso 4: await freirEmpanadas(empanadas)
Freír en aceite caliente hasta dorar
✅ Si todo sale bien:
console.log('Empanadas listas para servir')
3. Bloquecatch
Si algo falla:
console.error('Error en la preparación:', error)
4. Fin
Termina la ejecución del proceso
El error que estás encontrando sugiere que hay un problema al intentar usar multiprocessing.Pool en un contexto asíncrono. multiprocessing no se puede usar directamente con asyncio.
Para resolver esto, debes asegurarte de que estás utilizando await con funciones asíncronas. Alternativamente, si deseas ejecutar tareas en paralelo con asyncio, considera usar asyncio.create_task() o asyncio.gather() sin la necesidad de multiprocessing.
Asegúrate de que tu código esté estructurado para utilizar solo una de estas dos herramientas correctamente.
Gracias por tu aporte
Edgar Jonathan, la diferencia principal radica en cómo manejan el tiempo de espera y su impacto en la ejecución de otras tareas.
asyncio.sleep(): Es una función asíncrona. Cuando se llama, cede el control al bucle de eventos, permitiendo que otras tareas asíncronas se ejecuten mientras esta espera. Es ideal para operaciones de I/O.
time.sleep(): Es una función síncrona. Bloquea completamente el hilo de ejecución. Mientras time.sleep() está activo, ninguna otra tarea en ese hilo puede ejecutarse.
En resumen, asyncio.sleep() es no bloqueante y cooperativo, mientras que time.sleep() es bloqueante.
Comentario: Las líneas de código del resumen están en JavaScript.
# Creamos un Pool de Procesos basado en los núcleos de tu CPU
with concurrent.futures.ProcessPoolExecutor() as executor:
pedidos = [
procesar_pedido(executor, "PED-001", 350.50),
procesar_pedido(executor, "PED-002", 900.99),
procesar_pedido(executor, "PED-003", 500.00),
]
# Ejecutamos todos los pedidos concurrentemente
await asyncio.gather(*pedidos)
if __name__ == "__main__":
asyncio.run(main())
Soy yo, o todo esto está mal? Pr8mero muestra que se canceló la orden 1 y 3, pero luego que está calculando el precio y al finalizar muestra el precio de otra orden y que la orden 2 está cancelada
Recuerda que se usó random para simular que un objeto no este, los 3 que si estan funcionan, solo que el simulador hace como si no hubiera un producto para mostrar el mensaje.
Estuvo algo complejo de entender la clase sin embargo entendí un poco el sentido de la clase que era poder combinar archivos asíncronos con el multiproceso y quise hacer el mio propio
CODE:
import asyncio
import multiprocessing
import time
import random
asyncdefdescarga(file:str,id:int):print(f"Ejecutando descarga del archivo : {file}, id : {id}")await asyncio.sleep(random.randint(3,9))print(f"Descarga del archivo {file} finalizada con exito ")asyncdefvalidacion(file):print(f"Verificando {file} archivo...")await asyncio.sleep(random.randint(1,4))print("Archivo verificado")defpeso_archivo(file_peso):print("Calculando peso del archivo...") time.sleep(3)print("Archivo calculado")return file_peso *300asyncdefprocessing(file, peso,id):print("Procesando datos")await validacion(file)await descarga(file,id)with multiprocessing.Pool()as pool: result = pool.apply(peso_archivo,(peso,))print(f"Peso del archivo {file}: {result}")asyncdefmain():await asyncio.gather( processing("Cars 5",40,3), processing("PDF",50,2), processing("APK",1000,1))if __name__ =='__main__': asyncio.run(main())
Veo muy mal que usen funciones que no se explican previamente.