如何在 Python 的单独线程中启动烧瓶 api 服务器

Posted

技术标签:

【中文标题】如何在 Python 的单独线程中启动烧瓶 api 服务器【英文标题】:How to start flask api server in separate thread in Python 【发布时间】:2020-08-12 14:33:50 【问题描述】:

我正在开发一个 Python 项目,其中包括基于 pyqt5flask 的 API。在 UI 中,有startstop 按钮,按下它们将启动flask api 服务器并在单击停止按钮时停止。

from server import start_local_server
from multiprocessing import Process

"""
SOME CODE
"""

def start_server_btn_event(self):
    p1 = Process(target=start_local_server())
    p1.start()
    

def stop_server_btn_event(self):
    # Code to stop the api server

但上述操作会使整个 UI 无响应,我无法单击 UI 上的任何其他对象。如何在单独的线程或进程中单击按钮时运行 api 服务器,以便其他 UI 对象处于活动状态并可以执行其功能。谢谢

最小可重现示例:

app.py : 这包含启动本地服务器的 pyqt5 按钮

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from server import start_local_server
from PyQt5.QtCore import pyqtSlot
from multiprocessing import Process


class App(QWidget):

    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 button - pythonspot.com'
        self.left = 10
        self.top = 10
        self.width = 320
        self.height = 200
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        start_btn = QPushButton('Start Server', self)
        start_btn.move(100, 70)
        start_btn.clicked.connect(self.on_click_start_btn)

        stop_btn = QPushButton('Stop Server', self)
        stop_btn.move(200, 70)
        stop_btn.clicked.connect(self.on_click_stop_btn)

        fun_btn = QPushButton('Click to check responsiveness', self)
        fun_btn.move(150, 100)
        fun_btn.clicked.connect(self.on_click_fun_btn)

        self.show()

    @pyqtSlot()
    def on_click_start_btn(self):
        # Start server here
        p1 = Process(target=start_local_server())
        p1.start()


    @pyqtSlot()
    def on_click_stop_btn(self):
        print("Stop server ")

    @pyqtSlot()
    def on_click_fun_btn(self):
        print('If it is working, this means UI is responsive')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())

server.py:这是flask api服务器代码

import os
import datetime
from flask import Flask, jsonify
from flask_cors import CORS

app = Flask(__name__)
CORS(app)
wsgi_app = app.wsgi_app


@app.route('/api/status')
def check_status():
    return jsonify('status': 'ok', 'date': datetime.datetime.now().isoformat()), 200


def start_local_server():

    HOST = os.environ.get('SERVER_HOST', 'localhost')
    try:
        PORT = int(os.environ.get('SERVER_PORT', '5555'))
    except ValueError:
        PORT = 5555
    app.run(HOST, 80)

【问题讨论】:

正如文档所说:“[join] 方法会阻塞,直到进程 [...] 终止”。在主 Qt 线程中不应该发生任何阻塞功能。为什么叫它? @musicamante 对不起,我对join 有不同的理解。我已将其删除,但 UI 仍然无响应 请提供minimal, reproducible example。 @musicamante 我已经用最少的可重现示例更新了代码。请看一看。谢谢 @SAndrew Typo:将 p1 = Process(target=start_local_server()) 更改为 p1 = Process(target=start_local_server) 【参考方案1】:

我已经通过启动一个单独的线程来运行 API 服务器解决了这个问题:

run = True


def start_api_server():
    while run:
        start_local_server()
        
    time.sleep(1)
    print("SERVER HAS STOPPED")

@pyqtSlot()
def on_click_start_btn(self):
    Thread(target=start_api_server).start()

【讨论】:

以上是关于如何在 Python 的单独线程中启动烧瓶 api 服务器的主要内容,如果未能解决你的问题,请参考以下文章

Python 多处理管理器在烧瓶 API 中使用时显示错误

系统退出时无法停止python烧瓶线程

如何在线程中运行 python-socketio?

你如何序列化一个python烧瓶变量?

动态数据不会在烧瓶中改变

Python:定时在单独的线程中调用的函数