Выполнение длительной работы с интенсивными вычислениями в фоновом потоке - PullRequest
0 голосов
/ 01 марта 2019

Я написал REST API в среде Python Tornado, которая предсказывает ответ на вопрос из данного абзаца.


Вот код Python для обработчика Tornado:

def post(self):
    """
    This function predicts the response from the pre-trained Allen model
    """    
    try:
        request_payload = tornado.escape.json_decode(self.request.body)

        if (request_payload is None):
            return self._return_response(self, { "message": "Invalid request!" }, 400)

        context = request_payload["context"]
        question = request_payload["question"]

        if(context is None or not context):
            return self._return_response(self, { "message": "Context is not provided!" }, 400)

        if(question is None or not question):
            return self._return_response(self, { "message": "Question is not provided!" }, 400)

        # Compute intensive operation which blocks the main thread
        answer_prediction = predictor.predict(passage=str(context), question=str(question))
        best_answer = answer_prediction["best_span_str"] or "Sorry, no answer found for your question!"

        return self._return_response(self, { "answer": best_answer }, 200)

    except KeyError:
        #Return bad request if any of the keys are missing
        return self._return_response(self, { "message": 'Some keys are missing from the request!' }, 400)

    except json.decoder.JSONDecodeError:
        return self._return_response(self, { "message": 'Cannot decode request body!' }, 400)

    except Exception as ex:
        return self._return_response(self, { "message": 'Could not complete the request because of some error at the server!', "cause": ex.args[0], "stack_trace": traceback.format_exc(sys.exc_info()) }, 500)

Проблема в том, что строка:

answer_prediction = Forextor.predict (отрывок = str (контекст), question = str (вопрос))

Блокирует основной поток для входящих запросов и ожидает завершения этой длительной операции, одновременно блокируя другие запросы, и иногда прерывает текущий запрос.


Я прочитал этот ответ, детализирующий решение с помещением длительной операции в очередь, но я ее не получаю.

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

Вот мои вопросы:

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

Ответы [ 2 ]

0 голосов
/ 02 марта 2019

Запустить код блокировки в отдельном потоке.Используйте IOLoop.run_in_executor.

Пример:

from functools import partial

async def post(self):
    ...

    # create a partial object with the keyword arguments
    predict_partial = partial(predictor.predict, passage=str(context), question=str(question))

    answer_prediction = await IOLoop.current().run_in_executor(None, predict_partial)

    ...
0 голосов
/ 01 марта 2019

Я думаю, что вы должны превратить этот вызов API в асинхронный вызов и немедленно вернуться к вызывающей стороне с токеном.

Токен позже будет использовать токен для проверки (с помощью другого вызова API), завершена ли операция.

...