Как ждать метода в цикле?

У меня есть следующий метод, который генерирует данные для меня:

async def generate_url(self, video_id):
    data = await self.s3.generate_presigned_url(...video_id...)
    return data

def convert_to_json(self, urls):
    ids = [self.generate_url(url) for url in urls]
    ...

Как правильно ждать generate_url в convert_to_json?


person Community    schedule 04.04.2017    source источник
comment
Возможный дубликат вызова асинхронного метода в Python?   -  person Neil    schedule 04.04.2017
comment
предполагая, что convert_to_json был асинхронным, тогда вы просто ожидали бы для каждого элемента ids, я думаю, что async for data in ids: сработает.   -  person Tadhg McDonald-Jensen    schedule 04.04.2017


Ответы (3)


Вы можете использовать wait оболочку для списка задач. :

async def convert_to_json(self, urls):
    tasks = [self.generate_url(url) for url in urls]
    await asyncio.wait(tasks)

Или, если вы не можете пометить convert_to_json метод как async, подождите синхронно:

import asyncio

def convert_to_json(self, urls):
    loop = asyncio.get_event_loop()
    tasks = [self.generate_url(url) for url in urls]
    loop.run_until_complete(asyncio.wait(tasks))

Также вы можете попробовать реализовать async итератор < / a> и используйте его с синтаксисом async for, примерно так:

class Loader:
    def __init__(self, urls):
        self._urls = iter(urls)

    async def generate_url(self, video_id):
        data = await self.s3.generate_presigned_url(...video_id...)
        return data

    def __aiter__(self):
        return self

    async def __anext__(self):
        try:
            url = next(self._urls)
        except StopIteration:
            raise StopAsyncIteration
        data = await self.generate_url(url)
        return data

async for id in Loader(urls):
    print(id)
person VMAtm    schedule 05.04.2017

Если вы еще не используете цикл, попробуйте:

loop = asyncio.get_event_loop()
ids = loop.run_until_complete(asyncio.gather(*[self.generate_url(url) for url in urls]))

Или в сопрограмме:

ids = await asyncio.gather(*[self.generate_url(url) for url in urls])
person Udi    schedule 05.04.2017

Для меня это работало примерно так:

import asyncio

class A:
    def __init__(self):
        pass

    async def generate_url(self, video_id):
        data = await self.s3.generate_presigned_url(...video_id...)
        return data

    def add_to_ids(self, id):
        ids.append(id.result())

    def convert_to_json(self, urls):
        loop = asyncio.get_event_loop()

        ids = []
        tasks = []

        for url in urls:
            task = asyncio.ensure_future(self.generate_url(url))
            task.add_done_callback(self.add_to_ids)
            tasks.append(task)
        tasks = asyncio.gather(*tasks)

        loop.run_until_complete(tasks)
        loop.close()

a = A()
a.convert_to_json([1, 2, 3])

Наслаждаться!

person Yuval Pruss    schedule 04.04.2017