Python async - все запросы aiohttp отправляются сразу - PullRequest
0 голосов
/ 22 декабря 2018

Я работаю с python 3.7 и aiohttp , пытаюсь отправить асинхронные http-запросы от клиента на сервер.Это код сервера:

import asyncio
from aiohttp import web


async def hello(request):
    print('Got request')
    await asyncio.sleep(2)
    headers = {"content_type": "text/html"}
    response = web.Response(body='Hello', headers=headers)
    return response

app = web.Application()
app.router.add_route("GET", "/", hello)
web.run_app(app)

, а это код клиента:

import asyncio
from aiohttp import ClientSession
import time


async def fetch(url, session):
    print('Starting request')
    # some blocking calculation
    time.sleep(0.3)
    async with session.get(url) as response:
        print('Finished request')


async def run(r):
    url = "http://localhost:8080"
    tasks = []
    start = time.time()
    async with ClientSession() as session:
        for i in range(r):
            task = asyncio.create_task(fetch(url, session))
            tasks.append(task)

        responses = await asyncio.gather(*tasks)
    print(time.time()-start)

asyncio.run(run(10))

Однако у меня есть проблема, когда кажется, что все запросы «готовятся» одинза один раз, но затем отправляется все сразу.

Вот как выводится вывод, где «вычисление блокировки» находится внутри функции for «fetch»: gif1

И вот как это выглядит, когда внутри цикла for выполняется «вычисление блокировки»: gif2

У меня есть два вопроса.
1. Что вызывает эту разницу вповедение между gif1 и 2?
2. Почему все запросы отправляются одновременно?Я бы ожидал, что выход похож на это:

Стартовый запрос
Стартовый запрос
Стартовый запрос
Завершенный запрос
Завершенный запрос
Начальный запрос
Завершенный запрос
...

1 Ответ

0 голосов
/ 22 декабря 2018

Проблема заключается в том, что блокирующий код, такой как вызов time.sleep(0.3), не может выполняться параллельно asyncio, поскольку он блокирует весь поток цикла событий.Замените его на await asyncio.sleep(0.3), и проблема исчезнет.

Если у вас есть действительный код блокировки, который вы должны запустить внутри сопрограммы (например, вычисление NumPy), используйте await loop.run_in_executor(None, blocking_function) для выполнения вычисления в стороннем потоке и безопасного ожидания результата, позволяя другим сопрограммам добиваться прогресса в ожидании.

...