es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

asyncio, tarea periódica y obtener un valor de retorno

Quiero tener una tarea periódica que cree una lista de tareas pendientes.

Luego ejecuto cada tarea pendiente como una tarea separada.

Cuando la tarea periódica crea una nueva lista de tareas pendientes, quiero detener las tareas pendientes antiguas y ejecutar nuevas tareas pendientes.

Veo dos problemas.

  1. Solo las funciones period parecen ejecutarse (supongo que se debe a la línea gather).
  2. No puedo devolver un valor desde do_todo.

import asyncio

async def repeat(interval, func, *args, **kwargs):
while True:
await asyncio.gather(
func(*args, **kwargs),
asyncio.sleep(interval),
)

async def create_todo():
await asyncio.sleep(1)
print(‘Hola’)
todos = list(range(3))
return todos

async def g():
await asyncio.sleep(0.5)
print(‘Adiós’)
return 2

async def do_todo(x):
await asyncio.sleep(0.5)
print(f’hacer algo con {x}’)

async def main():
create_todo_task = asyncio.create_task(repeat(3, create_todo))
another_task = asyncio.create_task(repeat(2, g))

todos = await create_todo_task
print('tareas pendientes:', todos)
res2 = await another_task
print('resultado de g:', res2)

for todo in todos:
    t3 = asyncio.create_task(do_todo(todo))
    await t3

asyncio.run(main())

He tomado prestado el código de repeat de https://stackoverflow.com/a/55505152/433570.

Tags:  ,

Answer

  1. Avatar for davy.ai

    Para abordar el primer problema, solo la función pasada como argumento a repeat se ejecutará periódicamente. Dado que se utiliza la función gather, todas las corutinas pasadas a ella se ejecutarán simultáneamente. Por lo tanto, solo las funciones create_todo y g se ejecutarán periódicamente. Para solucionar esto, puedes crear una tarea separada para cada llamada a do_todo y ejecutarlas simultáneamente.

    Para abordar el segundo problema, do_todo no devuelve nada, pero puedes usar una cola para comunicarte entre las corutinas. En lugar de devolver un valor desde create_todo, puedes colocar la lista de tareas pendientes en una cola y luego leer desde la cola en main. do_todo también puede colocar sus resultados en otra cola, que main puede leer para recopilar los resultados.

    Aquí tienes un ejemplo de código actualizado:

    import asyncio
    from asyncio import Queue
    
    async def repeat(interval, func, *args, **kwargs):
        while True:
            await asyncio.gather(
                func(*args, **kwargs),
                asyncio.sleep(interval),
            )
    
    async def create_todo(queue: Queue):
        await asyncio.sleep(1)
        print('Creando lista de tareas pendientes')
        tareas_pendientes = list(range(3))
        await queue.put(tareas_pendientes)
    
    async def g():
        await asyncio.sleep(0.5)
        print('Adiós')
        return 2
    
    async def do_todo(x, results_queue: Queue):
        await asyncio.sleep(0.5)
        print(f'haciendo algo con {x}')
        await results_queue.put(x * 2)
    
    async def main():
        queue = Queue()
        results_queue = Queue()
        create_todo_task = asyncio.create_task(repeat(3, create_todo, queue))
        another_task = asyncio.create_task(repeat(2, g))
    
        while True:
            tareas_pendientes = await queue.get()
            print('tareas pendientes', tareas_pendientes)
            tareas = []
            while not results_queue.empty():
                resultado = await results_queue.get()
                print('resultado de do_todo', resultado)
            for tarea in tareas_pendientes:
                t = asyncio.create_task(do_todo(tarea, results_queue))
                tareas.append(t)
            await asyncio.gather(*tareas)
    
    asyncio.run(main())
    

    En este ejemplo, create_todo coloca la lista de tareas pendientes en queue, que main lee. do_todo coloca su resultado en results_queue, que main también lee. La función repeat llama a create_todo y g periódicamente, creando una nueva lista de tareas pendientes y ejecutando cualquier tarea nueva en paralelo con las existentes.

Comments are closed.