gunicorn не обрабатывает одновременные запросы одновременно

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

def app(environ, start_response):
    data = "Hello, World!\n"
    start_response("200 OK", [
        ("Content-Type", "text/plain"),
        ("Content-Length", str(len(data)))
    ])
    time.sleep(5)
    return iter([data])

Затем я запускаю gunicorn так:

gunicorn -w 4 myapp:app -k gevent

Когда я открываю две вкладки браузера и ввожу http://127.0.0.1:8000/ в обе из них и отправляю запросы почти одновременно, кажется, что запросы обрабатываются последовательно - один возвращается через 5 секунд, а другой возвращается через a еще 5 секунд.

Q. Я предполагаю, что сон не является дружественным? Но есть 4 воркера, и поэтому, даже если тип воркера был «синхронным», два воркера должны обрабатывать два запроса одновременно?


person swoop81    schedule 13.02.2013    source источник
comment
Вы нашли решение?   -  person Frank Cheng    schedule 24.09.2013


Ответы (3)


Я только что столкнулся с тем же, открыл здесь вопрос: огнестрельные рабочие . В результате получается, что браузер сериализует доступ к одной и той же странице. Я предполагаю, что, возможно, это как-то связано с кэшируемостью, т. Е. Браузер думает, что страница, вероятно, кэшируется, подождите, пока она загрузится, обнаружит, что это не так, поэтому он делает еще один запрос и так далее.

person CrazyCasta    schedule 13.04.2014
comment
Так обидно и так просто... :( - person jwg; 08.09.2017
comment
Спасибо @CrazyCasta. Я проверил ваш ответ, установив другой браузер и отправив запросы из двух разных браузеров (Chromium и Firefox) одновременно, и запросы обслуживаются параллельно. - person swoop81; 08.11.2017
comment
OMFG... это сводило меня с ума... было похоже... почему не работает многопоточность... спасибо! только что сделал: localhost:8000/?a=1 и localhost:8000/?b=1 и, конечно же, это работает - person Eric Longstreet; 09.02.2021

Попробуйте gevent.sleep вместо time.sleep.

Странно, что это происходит с -w 4, но -k gevent является асинхронным рабочим типом, поэтому возможно, что gunicorn отправляет оба запроса одному и тому же клиенту. Предполагая, что это происходит, time.sleep заблокирует ваш процесс, если вы не используете gevent.monkey.patch_all().

person amwinter    schedule 18.03.2014

При использовании gunicorn с неблокирующим рабочим типом, таким как gevent, будет использоваться ТОЛЬКО ОДИН процесс, обрабатывающий запросы, поэтому неудивительно, что ваша 5-секундная работа выполняется последовательно.

Асинхронный рабочий процесс полезен, когда ваша рабочая нагрузка невелика, а скорость запросов высока, в этом случае пушка может использовать время, потраченное впустую на ожидание ввода-вывода (например, ожидание того, что сокет станет доступным для записи, чтобы записать на него ответ), by переключиться на другого воркера для работы с другим запросом. переключившись на другой запрос, назначенный тому же воркеру.

ОБНОВЛЕНИЕ

Я ошибался.

При использовании gunicorn с неблокирующим типом воркера, с настройками воркера в gunicorn, каждый воркер — это процесс, который запускает отдельную очередь.

Таким образом, если time.sleep был запущен в другом процессе, он будет выполняться одновременно, но когда он запускается в одном рабочем процессе, он будет выполняться последовательно.

Проблема в том, что балансировщик нагрузки gunicorn мог не распределить два запроса на два рабочих процесса. Вы можете проверить текущий процесс с помощью os.getpid().

person tdihp    schedule 22.05.2014
comment
Gunicorn не использует только один процесс для обработки запросов; он использует номер, указанный вами как флаг -w. - person ron rothman; 08.11.2015
comment
@ron.rothman Это правда! Мое объяснение неверно, спасибо за упоминание. - person tdihp; 09.11.2015