Многопоточный сервер Python и асинхронная веб-розетка с клиентами Android - PullRequest
0 голосов
/ 19 февраля 2019

У меня есть клиентское приложение Android, которое отправляет некоторые данные на сервер в Python, где предполагается, что сервер Python должен выполнить длительную операцию / вычисления и вернуть результаты клиенту.

ToДля этого я сначала начал использовать Flask с Python на стороне сервера и асинхронную библиотеку Android на стороне клиента для отправки данных через HTTP POST.Однако я быстро заметил, что это не тот путь, потому что вычисления на сервере требуют времени, что приводит к таким проблемам, как клиент, получающий ошибки тайм-аута ... и т. Д.

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

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

1 Ответ

0 голосов
/ 19 февраля 2019

Прежде всего, если вы собираетесь выполнять процессорные операции в своем бэкэнде, вам [скорее всего] нужно запустить его в отдельном процессе .Не в теме / коро / и т.д.Причина в том, что python ограничен одним потоком за раз (вы можете прочитать больше о GIL ).Выполнение операции с большим количеством процессоров в многопоточности дает вашему бэкэнду некоторую доступность, но снижает производительность в целом.

  1. Простое / старое для этого решение - запустите ваш бэкэнд в несколько процессов (и потоков, предпочтительно).Т.е. разверните свою колбу с gunicorn , предоставьте ей несколько рабочих процессов.Таким образом, вы получите систему, способную выполнять number_of_processes - 1 тяжелые вычисления и при этом быть доступной для обработки запросов.Предел для процессов обычно составляет до cpu_cores * 2, в зависимости от архитектуры процессора.

  2. Чуть сложнее:

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

    Отличный интерфейс для этого будет ProcessPoolExecutor.Недостаток - труднее обрабатывать сбои / процессы, зависшие над

  3. Другой путь - очередь задач + рабочие.Один из наиболее часто используемых celery.Идея состоит в том, чтобы

    • открыть WS-соединение
    • поставить задачу в очередь
    • работник (в другом процессе или даже на другом физическом узле) в конце концов подхватывает задачу, вычисляет ее,положить результат в некоторый DB
    • основной процесс получает обратный вызов / результат длительного опроса по результату DB
    • основной процесс передает результат через WS

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

...