He estado probando todo tipo de cosas para poder usar un bucle asyncio dentro de otro bucle asyncio. La mayoría de las veces, mi prueba solo termina con errores, como:
RuntimeError: este bucle de eventos ya se está ejecutando
Mi código de ejemplo a continuación es solo la prueba base con la que comencé, para que pueda ver los conceptos básicos de lo que estoy tratando de hacer. Intenté muchas cosas después de esta prueba, era demasiado confuso, así que pensé que debería mantenerlo simple cuando pidiera ayuda. Si alguien me puede señalar en la dirección correcta, sería genial. ¡Gracias por tu tiempo!
import asyncio async def fetch(data): message = 'Hey {}!'.format(data) other_data = ['image_a.com', 'image_b.com', 'image_c.com'] images = sub_run(other_data) return {'message' : message, 'images' : images} async def bound(sem, data): async with sem: r = await fetch(data) return r async def build(dataset): tasks = [] sem = asyncio.Semaphore(400) for data in dataset: task = asyncio.ensure_future(bound(sem, data)) tasks.append(task) r = await asyncio.gather(*tasks) return r def run(dataset): loop = asyncio.get_event_loop() future = asyncio.ensure_future(build(dataset)) responses = loop.run_until_complete(future) loop.close() return responses async def sub_fetch(data): image = 'https://{}'.format(data) return image async def sub_bound(sem, data): async with sem: r = await sub_fetch(data) return r async def sub_build(dataset): tasks = [] sem = asyncio.Semaphore(400) for data in dataset: task = asyncio.ensure_future(sub_bound(sem, data)) tasks.append(task) r = await asyncio.gather(*tasks) return r def sub_run(dataset): loop = asyncio.get_event_loop() future = asyncio.ensure_future(sub_build(dataset)) responses = loop.run_until_complete(future) loop.close() return responses if __name__ == '__main__': dataset = ['Joe', 'Bob', 'Zoe', 'Howard'] responses = run(dataset) print (responses)Ejecutar loop.run_until_compete dentro de un bucle de eventos en ejecución bloquearía el bucle exterior, anulando así el propósito de usar asyncio. Por eso, los bucles de eventos asyncio no son recursivos, y no debería ser necesario ejecutarlos recursivamente. En lugar de crear un bucle de eventos interno, await una tarea en el existente.
En su caso, elimine sub_run y simplemente reemplace su uso:
images = sub_run(other_data)con:
images = await sub_build(other_data)Y funcionará bien, ejecutando las subrutinas y no continuando con la rutina externa hasta que la interna esté completa, como probablemente pretendías con el código de sincronización.