Как настроить бутылку с потоками для обработки в фоновом режиме - PullRequest
0 голосов
/ 27 мая 2019

Я пытаюсь настроить веб-сервис, который обрабатывает рендеринг в фоновом режиме, который занимает минуту.Пока идет рендеринг, я хочу, чтобы сервер мог обрабатывать запросы параллельно, возвращая Id {} not found или результат, если таковой имеется.

Учебники, которые я нашел, в основном обрабатывают простые запросы без особой обработки (http://bottlepy.org/docs/dev/async.html, с использованием sleep для эмуляции обработки).Так что я не совсем уверен, как реализовать многопоточность - нужно ли в потоке настраивать бутылочные маршруты?

С http://bottlepy.org/docs/dev/tutorial_app.html#server-setup я знаю, что сервер по умолчанию для бутылок однопоточный, поэтому япопытался переключиться на другой сервер (PasteServer).

from bottle import Bottle, run, PasteServer
from service import startWithDirectArgs, default_out, default_out_dir
import threading


class BakingThread(threading.Thread):
    # lock = threading.Lock()
    isProcessRunning = False
    resultDict = {}
    currentId = 0

    def __init__(self, bakingId: str, args):
        super().__init__()
        self.bakingId = bakingId
        self.args = args

    def run(self):
        # with BakingThread.lock:
        if BakingThread.isProcessRunning:
            return False

        BakingThread.processRunning = True
        print("\033[1;32;49m" +
              "Starting baking process with id {}".format(self.bakingId) +
              "\033[0;37;49m")
        result = startWithDirectArgs(self.args)
        # result = calculatePi(100_0000_00)
        BakingThread.resultDict[self.bakingId] = str(result)
        BakingThread.isProcessRunning = False
        print("\033[1;32;49m" +
              "Finished baking process with id {}".format(self.bakingId) +
              "\033[0;37;49m")
        return result


def getUniqueId() -> str:
    BakingThread.currentId += 1
    return str(BakingThread.currentId)


def calculatePi(n: int) -> float:
    halfPi = 1.0
    zaehler = 2.0
    nenner = 1.0
    for i in range(n):
        halfPi *= zaehler / nenner
        if i % 2:
            zaehler += 2.0
        else:
            nenner += 2.0
    return 2.0 * halfPi


app = Bottle()


@app.route("/bakeFile/<fileParam>")
def bakeFile(fileParam: str):
    # args = {"file": fileParam, "out": default_out_dir + default_out}
    args = {
        "file": "build/igmodels/AOMaps/Scene.igxc",  # fileParam,
        "out": default_out_dir + default_out
    }
    print(args)
    cid = getUniqueId()
    bt = BakingThread(cid, args)
    bt.start()
    bt.join()


@app.route("/bakeUrl/<urlParam>")
def bakeUrl(urlParam: str):
    args = {"url": urlParam, "out": default_out_dir + default_out}
    print(args)
    cid = getUniqueId()
    bt = BakingThread(cid, args)
    bt.start()
    bt.join()


@app.route("/pullState/<bakingId>")
def pullState(bakingId: str):
    print("\033[1;33;49m" + "pullState id {}".format(BakingThread.currentId) +
          "\033[0;37;49m")
    result = BakingThread.resultDict.get(bakingId,
                                         "Id {} not found".format(bakingId))
    return result


app.run(host="localhost", port=8080, debug=True, server=PasteServer)

Я ожидаю, что смогу запустить http://localhost:8080/bakeFile/3dGeometryFileName, и пока идет рендеринг, я ожидаю вызова http://localhost:8080/pullState/1, чтобы ответить Id 1 not found.После завершения рендеринга тот же вызов должен вернуть результат.

Редактировать: Процесс рендеринга был реализован на C ++, связан с PyBind.Глобальная блокировка интерпретатора (GIL) препятствовала одновременному выполнению рендеринга и веб-обслуживания, поэтому я добавил py::gil_scoped_release release; до и py::gil_scoped_acquire acquire; после дорогостоящих вычислений в коде C ++.В приведенном выше коде я добавил фрагмент кода для вычисления pi непосредственно в python без C ++ / PyBind, чтобы разработчик bottlePy мог указать мне на эту вещь GIL.(Thx Marcel)

1 Ответ

0 голосов
/ 27 мая 2019

Решил.

Процесс рендеринга был реализован на C ++, связан с PyBind. Глобальная блокировка интерпретатора (GIL) предотвращала одновременное выполнение рендеринга и веб-обслуживания, поэтому я добавил py::gil_scoped_release release; до и py::gil_scoped_acquire acquire; после дорогостоящих вычислений в коде C ++. В приведенном выше коде я добавил фрагмент кода для вычисления pi непосредственно в python без C ++ / PyBind, чтобы разработчик bottlePy мог указать мне на эту вещь GIL. (Thx Marcel)

...