Flask 中的线程不与 UWSGI 一起工作但在命令行上工作

Threading in Flask not working with UWSGI but working on commandline

我有一个 Flask 应用程序,当在命令行上 运行 时工作正常,但是当它通过 uWSGI 运行 时它不能正确响应请求或者工作线程不工作适当地。我重写了一个简单的 proof-of-concept/failure 程序来演示这个问题:

from datetime import datetime
from threading import Event, Thread

from flask import Flask


class JobManager:
    def __init__(self):
        self.running = False
        self.event = Event()

    def start(self):
        self.running = True
        while self.running:
            print("Processing Job at", datetime.now().strftime('%c'))
            self.event.clear()
            self.event.wait(5)
            if self.event.is_set():
                print("Interrupted by request!")

    def stop(self):
        self.running = False
        self.event.set()


app = Flask(__name__)
jobs = JobManager()

t = Thread(target=jobs.start)
t.start()

@app.route('/')
def hello_world():
    global jobs
    jobs.event.set()

    return "I'm alive at " + datetime.now().strftime('%c')


if __name__ == '__main__':
    app.run()

我希望调用 / 路由会在控制台上打印 "Interrupted by request!" 但它只是挂起,即使作业应该 运行 在单独的线程中运行。

我的 uWSGI 配置是:

[uwsgi]
module = app:app

master = true
processes = 5
threads = 2

socket = 0.0.0.0:5000
protocol = http

reload-mercy = 5
worker-reload-mercy = 5

die-on-term = true
enable-threads = true
thunder-lock = true

logto = /home/user/dev/flask-thread/uwsgi_log.log
logto2 = /home/user/dev/flask-thread/uwsgi2_log.log

env = PATH=/home/user/dev/flask-thread/env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

然后我在 venv 中 运行 uWSGI:uwsgi --ini uwsgi-test.ini

如果我使用 python app.py 并使用内置的 flask 开发服务器,它将工作。

我唯一的猜测是它与 GIL 与 uWSGI 交互有关,但这是一个疯狂的猜测,我不知道如何阻止它。

对我来说,使用 uwsgi 标志 --lazy 有效。

uwsgi foo.ini --socket=0.0.0.0:5000 --protocol=http --lazy -w wsgi

解释:

引自http://lists.unbit.it/pipermail/uwsgi/2011-June/002307.html

single process (no master):

the process creates the thread in which the WSGI callable put data.

This is ok

with master process:

the master load the app and generate the thread. Then it forks one or more workers. This workers are new processes with no relation with the thread spawned in the master. So your data will go nowhere (only the master can access the initial thread).

You have two way to follow:

1) add --lazy to the command line, in this way your app will be loaded after master's fork, so each worker will get its thread.

2) rewrite your app to use the uwsgi.post_fork_hook feature.

对我来说,lazy 没有用,我不想经历使用 post_fork_hook 功能的麻烦,但我确实在 [=13= 上找到了以下内容] :

By default the Python plugin does not initialize the GIL. This means your app-generated threads will not run. If you need threads, remember to enable them with enable-threads. Running uWSGI in multithreading mode (with the threads options) will automatically enable threading support. This “strange” default behavior is for performance reasons, no shame in that.

确实没有什么可耻的,但仍然令人心痛。长话短说,我在我的配置文件中设置了 enable-thread = true,我的线程立即可靠地开始旋转