【问题标题】:Threading in Flask not working with UWSGI but working on commandlineFlask 中的线程不能与 UWSGI 一起使用,但可以在命令行上使用
【发布时间】:2018-08-20 12:56:09
【问题描述】:

我有一个 Flask 应用程序,在命令行上运行时可以正常工作,但是当它通过 uWSGI 运行时,它不能正确响应请求或工作线程不能正常工作。我重写了一个简单的概念验证/故障程序来演示这个问题:

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()

我希望调用 / 路由会打印“被请求中断!”在控制台上,但它只是挂起,即使作业应该在单独的线程中运行。

我的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 并使用内置的烧瓶开发服务器,它将起作用。

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

【问题讨论】:

    标签: python-3.x flask uwsgi python-multithreading gil


    【解决方案1】:

    对我来说,使用 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:

    单进程(无主):

    进程创建线程,WSGI 可调用对象在其中放置数据。

    没关系

    与主进程:

    master 加载应用程序并生成线程。然后它分叉一个或 更多的工人。这个工人是新的进程,与 主线程中产生的线程。所以你的数据将无处可去(只有 master 可以访问初始线程)。

    你有两种方法可以跟随:

    1) 在命令行中添加--lazy,这样你的应用就会被加载 在master的fork之后,所以每个worker都会得到它的线程。

    2) 重写您的应用以使用 uwsgi.post_fork_hook 功能。

    【讨论】:

    • 我最终使用了 uwsgi.post_fork_hook,现在效果很好 :) 感谢您的帮助。我很困惑它是如何将工人分开以及需要做什么。
    • 你成就了我的一天! --lazy 有效。最后,uwsgi 很好地处理了他的工作,即在需要时重新连接/重新创建 sysPipe。
    【解决方案2】:

    对我来说,lazy 不起作用,我不想经历使用 post_fork_hook 功能的麻烦,但我确实在https://uwsgi-docs.readthedocs.io/en/latest/ThingsToKnow.html 上找到了以下内容:

    默认情况下,Python 插件不会初始化 GIL。这意味着您的应用程序生成的线程将不会运行。如果您需要线程,请记住使用 enable-threads 启用它们。在多线程模式下运行 uWSGI(使用线程选项)将自动启用线程支持。这种“奇怪”的默认行为是出于性能原因,这并不丢人。

    确实不丢脸,但还是心痛。长话短说,我在配置文件中设置了enable-thread = true,我的线程立即开始可靠地启动

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-20
      • 1970-01-01
      • 2018-10-13
      • 1970-01-01
      • 1970-01-01
      • 2019-11-14
      • 2012-07-14
      相关资源
      最近更新 更多