Как вернуть несколько значений из асинхронной функции в синхронный контекст? - PullRequest
0 голосов
/ 30 июня 2019

Мне нужно собрать результаты асинхронных вызовов и вернуть их в обычную функцию - соединение разделов асинхронного и синхронизирующего кода смущает меня.

Первая попытка с безобразным параметром inout.

import asyncio
import aiohttp

async def one_call(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            txt = await response.text()
            return txt[0:20]


async def do_all(result_inout):
    urls = ["https://cnn.com", "https://nyt.com", "http://reuters.com"]
    out = await asyncio.gather(*[one_call(url) for url in urls])
    result_inout += out

if __name__ == "__main__":
    result_inout = []
    asyncio.run(do_all(result_inout))

    print(result_inout)

Вторая попытка, но с прямым использованием цикла обработки событий, который не рекомендуется для кода приложения.

if __name__ == "__main__":
    # same imports, same one_call, same urls
    loop = asyncio.get_event_loop()

    aggregate_future = asyncio.gather(*[one_call(url) for url in urls])
    results = loop.run_until_complete(aggregate_future)
    loop.close()

    print(results) 

Каков наилучший способ сделать это?

1 Ответ

2 голосов
/ 30 июня 2019

Не нужно result_inout, вы можете просто использовать out = asyncio.run(do_all()), чтобы получить return res из do_all.

import asyncio
import aiohttp

async def one_call(url):
    await asyncio.sleep(2)
    return 0


async def do_all():
    urls = ["https://cnn.com", "https://nyt.com", "http://reuters.com"]
    out = await asyncio.gather(*[one_call(url) for url in urls])
    return out

if __name__ == "__main__":
    out = asyncio.run(do_all())

    print(out)

будет [0, 0, 0].

...