Ainvain
@Ainvain

Как параллельно обрабатывать API запросы?

Пытаюсь написать сервис для классификации текста (для чат-бота). Есть желание сделать его многопоточным, чтобы поднять производительность.
Насколько понял, waitress создает несколько потоков для обработки запросов. Но в запросах используется один и тот же объект classific (модель для классификации). При этом внутри объекта хранятся словари для котроля контекста диалога в рамках сессии (по session_id). Допустим, их можно вынести отдельно.

import argparse
import yaml
from waitress import serve
from flask import Flask, request
from flask_restful import Api, Resource, reqparse
app = Flask(__name__)
api = Api(app)

class Detect(Resource):
    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument("session_id")
        parser.add_argument("phrase")
        params = parser.parse_args()

        return classific.detect_intent(
            phrase = params['phrase'], 
            session_id = params['session_id']), 200
    
    def get(self):
        phrase = request.args.get('phrase')
        session_id = request.args.get('session_id')
        if phrase:
            return classific.detect_intent(
                phrase = phrase, 
                session_id = session_id), 200
        else:
            return "No phrase in request", 400

api.add_resource(Detect, '/', '/detect')
# часть кода опущена

if __name__ == '__main__':    
    args = parser.parse_args()
    lin_model_path: str = args.liner_model_path
    regexp_path: str = args.regexp_path    
    agent_name: str =  args.agent_name

    model = nlu.model(lin_model_path) if lin_model_path else None
    regexp_data = None
    if regexp_path:
        with open(regexp_path, mode='r', encoding='UTF-8') as file:
            regexp_data = yaml.safe_load(file)
    classific = Classificator(linear_model=model, regexp_patterns=regexp_data, agent_name=agent_name)    

    
    print('Запуск сервера')
    serve(app, host=args.host, port=args.port)


Как можно сделать так, чтобы каждый из потоков waitress использовал отдельный, заранее заданный экземпляр Classificator (копия classific), а изменяемые данные (контекст диалога) хранились в разделяемой переменной? Ещё, как вариант, запросы с одинаковым session_id могли бы обрабатываться в одном классификаторе, а разные сессии могли параллельно обрабатываться в разных потоках.
  • Вопрос задан
  • 122 просмотра
Пригласить эксперта
Ответы на вопрос 1
Vindicar
@Vindicar
RTFM!
Я бы сделал несколько по другому.
Оформил бы отдельно рабочий поток/процесс, и заставил бы их общаться через пару очередей (классический паттерн producer-consumer). Подходящие классы очереди можно найти в multiprocessing (ну или в threading, если ты очень хочешь потоки вместо процессов).

Основной (корневой) процесс запускает рабочие процессы, потом слушает входящие запросы. Получив запрос, кидает его в очередь. Первый свободный процесс извлекает запрос из очереди, обрабатывает, отправляет ответ на запрос, и снова ждёт появления элемента в очереди. Проблема в том, что при использовании процессов придётся передавать между ними сложный объект Request - я не уверен, что это будет просто. Можешь попробовать потоки, но в питоне потоки не всегда хорошо работают.

Нужно будет подумать над тем, где будут узкие места. Я вижу два - собственно работа классификатора, и обмен данными с клиентами. Первое ты обходишь, второе можно отчасти обойти через асинхронную работу (flask это умеет).
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
25 апр. 2024, в 11:02
5000 руб./за проект
25 апр. 2024, в 10:42
150000 руб./за проект
25 апр. 2024, в 10:41
2000 руб./за проект