получить завершенные параллельные запросы aiohttp после тайм-аута - PullRequest
2 голосов
/ 23 января 2020

Я использую aiohttp для выполнения некоторых параллельных HTTP-запросов.

Мне нужно установить глобальное время ожидания (на ClientSession), чтобы не превысить порог.

Проблема в том, что я хотел бы принять (частичные в сеансах) ответы, которые я завершил до порогового значения, например, если в сеансе содержится 10 запросов и до истечения времени ожидания, которое я выполнил 5 из них, я хочу взять результат этих 5. Но я не понял, как это сделать.

Код, который я использую, выглядит примерно так:

import aiohttp
import asyncio
import requests

async def fetch(session):
    async with session.get("https://amazon.com") as response:
        return response.status

async def main(n, timeout):
    async with aiohttp.ClientSession(timeout=timeout) as session:
        return await asyncio.gather(*(fetch(session) for _ in range(n)))

timeout = aiohttp.ClientTimeout(total=0.4)
res = asyncio.run(main(10, timeout))
print(res)

С timeout = 0.4 это вызывает asyncio.TimeoutError, и я не знаю, как получить частично выполненные ответы.

Например, если установить тайм-аут на 5 секунд, все запросы будут выполнены, и я получу список из десяти 200.

Спасибо

1 Ответ

1 голос
/ 23 января 2020

Используйте asyncio.wait вместо asyncio.gather

Также см. этот QA для получения дополнительной информации о различиях.

Примечание: ожидание timeout аргумент выражается в секундах.

Прежде всего, вам вообще может не потребоваться указывать тайм-аут для ClientSession.

Переработанный код (для увеличения дисперсии времени отклика) Я добавил несколько разных источников, и 20 запросов были выполнены)

import asyncio
import random
import aiohttp
import requests

sources = ["amazon.com", "hotmail.com", "stackoverflow.com"]

async def fetch(session):
    rnd = random.choice(sources)
    async with session.get(f"https://{rnd}") as response:
        return response.status

async def main(n, timeout):
    async with aiohttp.ClientSession() as session:
        completed, pending = await asyncio.wait(
            [fetch(session) for _ in range(n)],
            timeout=timeout
        )
    for t in pending:  # cancel the pending tasks
        t.cancel()
    return [t.result() for t in completed]

timeout = 0.5
res = asyncio.run(main(20, timeout))
print(res)

с увеличением значений timeout, поскольку 0,3, 0,5 и 0,8 производят

(.venv) async_req_timeout $ python async_req_timeout.py 
[200, 200]

(.venv) async_req_timeout $ python async_req_timeout.py 
[200, 200, 200, 200, 200, 200, 200, 200, 200, 200]

(.venv) (base) async_req_timeout $ python async_req_timeout.py 
[200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200]
...