Sanic Python в Windows, синхронное поведение на одной и той же конечной точке — ожидается ли это?

Тривиальный вопрос и, вероятно, задавался несколько раз. Я понимаю, что Sanic может работать на Windows (т.е. обнаруживать отсутствие uvloop, но тем не менее отступать и нажимать).

Мой вопрос в том, будет ли он по-прежнему обслуживать запросы асинхронно в Windows....? Ответ, кажется, да - в конце концов, это асинхронный фреймворк.

Однако, скажем, у меня есть конечная точка, которая просто спит, т.е. asyncio.sleep(10) и возвращается. Если я вызову эту конечную точку (/) дважды подряд, первый ответ вернется через 10 секунд, и только после этого начнется обработка второго запроса. Таким образом, второй запрос возвращается примерно через 20 секунд (синхронное поведение).

Теперь, если я сделал то же самое, т.е. запустил запрос на 2 независимых конечных точках, скажем (/i и /) - они оба начинают обработку, как только поступает запрос, первый занимает 10 секунд, прежде чем ответить (как и ожидалось), а затем второй возвращается сразу после первого (асинхронное поведение).

Я как бы ожидал, что асинхронные задачи обработчика запросов будут переданы в цикл событий и, следовательно, будут иметь такое же асинхронное поведение даже при быстром вызове одной и той же конечной точки дважды.

Я что-то упустил здесь?

from sanic import Sanic
from sanic.response import json
import asyncio
app = Sanic("X")

@app.route("/")
async def test(request):
    print("request rcvd")
    await asyncio.sleep(10)
    return json({"hello": "world"})

@app.route("/i")
async def test(request):
    print("request /i rcvd")
    await asyncio.sleep(10)
    return json({"hello": "i"})

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

person doctarius    schedule 02.02.2020    source источник


Ответы (1)


Если я вызову эту конечную точку (/) дважды подряд, первый ответ вернется через 10 секунд, и только тогда начнется обработка второго запроса.

Я попробовал ваш код и, боюсь, не могу воспроизвести это поведение. У меня оба запроса запускаются сразу и оба возвращают результаты через 10 секунд.

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


server.py

from sanic import Sanic
from sanic.response import json
import asyncio
from datetime import datetime


app = Sanic("X")


@app.route("/")
async def test(request):
    print("request rcvd")
    await asyncio.sleep(10)
    return json({"/": str(datetime.now())})


@app.route("/i")
async def test(request):
    print("request /i rcvd")
    await asyncio.sleep(10)
    return json({"/i": str(datetime.now())})


if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8000)

client.py

import asyncio
import aiohttp
from datetime import datetime


async def get(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()


async def main():
    print(f'Started: {datetime.now()}')

    results = await asyncio.gather(
        get('http://127.0.0.1:8000/'),
        get('http://127.0.0.1:8000/'),
    )

    print(f'Finished: {results}')


asyncio.run(main())

Результат:

Started: 2020-02-02 16:50:29.087871
Finished: ['{"/":"2020-02-02 16:50:41.137824"}', '{"/":"2020-02-02 16:50:41.137824"}']

Я также получил ожидаемое поведение (запросы на одной и той же конечной точке запускаются/завершаются параллельно), когда я проверял все вручную через браузер.

person Mikhail Gerasimov    schedule 02.02.2020