aiohttp с asyncio и семафорами, возвращающими список, заполненный Nones - PullRequest
1 голос
/ 15 мая 2019

У меня есть скрипт, который проверяет код состояния для пары сотен тысяч предоставляемых веб-сайтов, и я пытался интегрировать семафор в поток, чтобы ускорить обработку. Проблема в том, что всякий раз, когда я интегрирую семафор, я просто получаю список, заполненный объектами None, и я не совсем уверен, почему.

Я в основном копирую код из других источников, так как я еще не полностью использую асинхронное программирование, но кажется, что при отладке я должен получать результаты из функции, но что-то идет не так, когда я собираю Результаты. Я пытался жонглировать своим циклом, сбором, обеспечением фьючерсов и т. Д., Но, похоже, ничего не возвращает список вещей, которые работают.

async def fetch(session, url):
    try:
        async with session.head(url, allow_redirects=True) as resp:
            return url, resp.real_url, resp.status, resp.reason
    except Exception as e:
        return url, None, e, 'Error'


async def bound_fetch(sem, session, url):
    async with sem:
        await fetch(session, url)


async def run(urls):
    timeout = 15
    tasks = []

    sem = asyncio.Semaphore(100)
    conn = aiohttp.TCPConnector(limit=64, ssl=False)

    async with aiohttp.ClientSession(connector=conn) as session:
        for url in urls:
            task = asyncio.wait_for(bound_fetch(sem, session, url), timeout)
            tasks.append(task)

        responses = await asyncio.gather(*tasks)

    # responses = [await f for f in tqdm.tqdm(asyncio.as_completed(tasks), total=len(tasks))]
    return responses

urls = ['https://google.com', 'https://yahoo.com']

loop = asyncio.ProactorEventLoop()
data = loop.run_until_complete(run(urls))

Я закомментировал компонент индикатора выполнения, но эта реализация возвращает желаемые результаты, когда семафор отсутствует.

Любая помощь будет принята с благодарностью. Я яростно читаю об асинхронном программировании, но пока не могу обдумать это.

1 Ответ

1 голос
/ 15 мая 2019

Вы должны явно возвращать результаты ожидания сопрограмм.

Заменить этот код ...

async def bound_fetch(sem, session, url):
    async with sem:
        await fetch(session, url)

... с этим:

async def bound_fetch(sem, session, url):
    async with sem:
        return await fetch(session, url)
...