ограничить количество одновременных запросов aiohttp - PullRequest
0 голосов
/ 05 мая 2018

Я загружаю изображения с помощью aiohttp, и мне было интересно, есть ли способ ограничить количество открытых запросов, которые еще не завершены. Это код, который у меня сейчас есть:

async def get_images(url, session):

    chunk_size = 100

    # Print statement to show when a request is being made. 
    print(f'Making request to {url}')

    async with session.get(url=url) as r:
        with open('path/name.png', 'wb') as file:
            while True:
                chunk = await r.content.read(chunk_size)
                if not chunk:
                    break
                file.write(chunk)

# List of urls to get images from
urls = [...]

conn = aiohttp.TCPConnector(limit=3)
loop = asyncio.get_event_loop()
session = aiohttp.ClientSession(connector=conn, loop=loop)
loop.run_until_complete(asyncio.gather(*(get_images(url, session=session) for url in urls)))

Проблема в том, что я добавил оператор печати, чтобы показать мне, когда выполняется каждый запрос, и он делает почти 21 запрос одновременно, вместо 3, которыми я хочу ограничить его (т. Е. Один раз изображение загрузка завершена, можно перейти к следующему URL в списке, чтобы получить). Мне просто интересно, что я здесь делаю не так.

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

Ваш лимит работает правильно. Вы сделали ошибку при отладке.

Как отметил Михаил Герасимов в комментарии , вы поставили вызов print() в неправильном месте - он должен быть внутри session.get() контекста.

Чтобы убедиться, что лимит соблюдается, я проверил ваш код на простом сервере регистрации - и тест показывает, что сервер получает именно то количество соединений, которое вы установили в TCPConnector. Вот тест:

import asyncio
import aiohttp
loop = asyncio.get_event_loop()


class SilentServer(asyncio.Protocol):
    def connection_made(self, transport):
        # We will know when the connection is actually made:
        print('SERVER |', transport.get_extra_info('peername'))


async def get_images(url, session):

    chunk_size = 100

    # This log doesn't guarantee that we will connect,
    # session.get() will freeze if you reach TCPConnector limit
    print(f'CLIENT | Making request to {url}')

    async with session.get(url=url) as r:
        while True:
            chunk = await r.content.read(chunk_size)
            if not chunk:
                break

urls = [f'http://127.0.0.1:1337/{x}' for x in range(20)]

conn = aiohttp.TCPConnector(limit=3)
session = aiohttp.ClientSession(connector=conn, loop=loop)


async def test():
    await loop.create_server(SilentServer, '127.0.0.1', 1337)
    await asyncio.gather(*(get_images(url, session=session) for url in urls))

loop.run_until_complete(test())
0 голосов
/ 05 мая 2018

asyncio.Semaphore решает именно эту проблему.

В вашем случае это будет примерно так:

semaphore = asyncio.Semaphore(3)


async def get_images(url, session):

    async with semaphore:

        print(f'Making request to {url}')

        # ...

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

...