Python - 如何在不阻塞线程的情况下使用 FastAPI 和 uvicorn.run?

Leu*_*uko 7 python multiprocessing fastapi uvicorn

我正在寻找将 uvicorn.run() 与 FastAPI 应用程序一起使用但没有 uvicorn.run() 阻塞线程的可能性。我已经尝试使用进程、子进程和线程,但没有任何效果。我的问题是我想从另一个进程启动服务器,该进程在启动服务器后应该继续执行其他任务。另外,我在从另一个进程关闭服务器时遇到了问题。

有没有人知道如何使用 uvicorn.run() 非阻塞以及如何从另一个进程中阻止它?

问候 LeukoClassic

Eli*_*jas 11

@HadiAlqa​​ttan 给出的方法将不起作用,因为uvicorn.run期望在主线程中运行。signal only works in main thread会引发诸如此类的错误。

正确的做法是:

import contextlib
import time
import threading
import uvicorn

class Server(uvicorn.Server):
    def install_signal_handlers(self):
        pass

    @contextlib.contextmanager
    def run_in_thread(self):
        thread = threading.Thread(target=self.run)
        thread.start()
        try:
            while not self.started:
                time.sleep(1e-3)
            yield
        finally:
            self.should_exit = True
            thread.join()

config = Config("example:app", host="127.0.0.1", port=5000, log_level="info")
server = Server(config=config)

with server.run_in_thread():
    # Server is started.
    ...
    # Server will be stopped once code put here is completed
    ...

# Server stopped.
Run Code Online (Sandbox Code Playgroud)

使用 pytest 夹具在本地运行实时测试服务器非常方便:

# conftest.py
import pytest

@pytest.fixture(scope="session")
def server():
    server = ...
    with server.run_in_thread():
        yield
Run Code Online (Sandbox Code Playgroud)

积分:uvicorn#742florimondmanca


Had*_*tan 1

根据Uvicorn文档,没有以编程方式停止服务器的方法。相反,您只能通过按ctrl + c (官方)来停止服务器。

但我有一个技巧可以使用多处理标准库和这三个简单的函数以编程方式解决这个问题:

  • 运行服务器的运行函数。
  • 用于启动新进程(启动服务器)的启动函数。
  • 用于加入进程的停止函数(停止服务器)。
from multiprocessing import Process
import uvicorn

# global process variable
proc = None


def run(): 
    """
    This function to run configured uvicorn server.
    """
    uvicorn.run(app=app, host=host, port=port)


def start():
    """
    This function to start a new process (start the server).
    """
    global proc
    # create process instance and set the target to run function.
    # use daemon mode to stop the process whenever the program stopped.
    proc = Process(target=run, args=(), daemon=True)
    proc.start()


def stop(): 
    """
    This function to join (stop) the process (stop the server).
    """
    global proc
    # check if the process is not None
    if proc: 
        # join (stop) the process with a timeout setten to 0.25 seconds.
        # using timeout (the optional arg) is too important in order to
        # enforce the server to stop.
        proc.join(0.25)

Run Code Online (Sandbox Code Playgroud)


有了同样的想法,你可以

  • 使用线程标准库而不是使用多处理标准库。

  • 将这些函数重构为一个类。


使用示例:

from time import sleep

if __name__ == "__main__":
    # to start the server call start function.
    start()
    # run some codes ....
    # to stop the server call stop function.
    stop()
Run Code Online (Sandbox Code Playgroud)



您可以阅读更多有关: