• Как использовать asyncio в стандартном for цикле?

    nick1994209
    @nick1994209
    Разработчик: python, golang, js
    import asyncio
    
    import aiohttp
    
    
    async def get_urls_statistic(urls: list):
        """
        Получение статистики по сайтам
    
        :param urls: список сайтов для которых вернется статистика
        :return: {url: {'gtm_speed': ..., 'pagespeed_desctop': ..., 'pagespeed_mobile': ...}}
        """
    
        # одновременно обрабатываем все сайты, которые бросили в asyncio
        # sites_statistics - это список словарей, расположенные по порядку сайтов
        sites_statistics = await asyncio.gather(*[get_site_statistic(url) for url in urls])
        # объединяем url и его статистику
        return {url: statistic for url, statistic in zip(urls, sites_statistics)}
    
    
    async def get_site_statistic(url) -> dict:
        # так же одновременно делаем запросы на получение разных статистик
        gtm_speed, pagespeed_desctop, pagespeed_mobile = await asyncio.gather(
            get_site_speed(url),
            get_pagespeed_statistic(url, 'desctop'),
            get_pagespeed_statistic(url, 'mobile')
        )
        return {
            'gtm_speed': gtm_speed,
            'pagespeed_desctop': pagespeed_desctop,
            'pagespeed_mobile': pagespeed_mobile,
        }
    
    
    async def get_site_speed(url):
        """
        тут типо должны использовать сайт для измерения скорости и потом парсить ответ
    
        """
        gtm_url = ''  # prepare your
        response = await get_response(url)
        # ... parse response
        return response.content
    
    
    async def get_pagespeed_statistic(site_url, version):
        response = await get_response(site_url)
        # ... parse response
        return response.content
    
    
    async def get_response(url, base_semaphore=asyncio.Semaphore(5)) -> aiohttp.ClientResponse:
        """
        Получение тела ответа
        
        :param url: куда делаем запрос
        :param base_semaphore: семафор, который не будет давать делать
            больше 5 подключений к сайтам (а то нас забанят)
    
        в данном примере base_semaphore - переменная, которая один раз инициализировалась,
        и при каждом вызове функции get_response будет использоваться base_semaphore
        """
    
        # код ниже может быть запущен одновременно не больше 5 раз, если больше
        # то будем ждать, завершения
        async with base_semaphore:
            async with aiohttp.ClientSession() as session:
                async with session.get(url) as response:
                    return response
    
    
    if __name__ == '__main__':
        # # получаем asyncio цикл событий
        loop = asyncio.get_event_loop()
        # говорим циклу событий: работай пока все не сделаешь и верни мне результат!!!
        statistics = loop.run_until_complete(get_urls_statistic([
            'https://pythondigest.ru/',
            'https://yandex.ru',
            # ...
        ]))
        print(statistics)
    
        # с python3.7 рекумондуют использовать asyncio.run
    Ответ написан
    Комментировать