【问题标题】:How to achieve true multiprocessing in uWsgi?如何在uWsgi中实现真正的多处理?
【发布时间】:2014-11-14 08:41:50
【问题描述】:

我有一个用 Flask 编写的 python 脚本,它需要一些准备工作(连接到数据库、获取一些其他资源等)才能真正接受请求。

我在带有 wsgi 的 Apache HTTPD 下使用它。阿帕奇配置:

WSGIDaemonProcess test user=<uid> group=<gid> threads=1 processes=4
WSGIScriptAlias /flask/test <path>/flask/test/data.wsgi process-group=test

而且运行良好:Apache 会启动 4 个完全独立的进程,每个进程都有自己的数据库连接。

我现在正在尝试切换到 uwsgi + nginx。 nginx 配置:

location /flask/test/ {
    include uwsgi_params;
    uwsgi_pass unix:/tmp/uwsgi.sock;
}

uwsgi:

uwsgi -s /tmp/uwsgi.sock --mount /flask/test=test.py --callable app --manage-script-name --processes=4 --master

简化脚本test.py:

from flask import Flask, Response
app = Flask(__name__)


def do_some_preparation():
    print("Prepared!")


@app.route("/test")
def get_test():
    return Response("test")

do_some_preparation()

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

我希望看到“准备好了!” 4次输出。但是,uwsgi 不这样做,输出:

Python main interpreter initialized at 0x71a7b0
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 363800 bytes (355 KB) for 4 cores
*** Operational MODE: preforking ***
mounting test.py on /flask/test
Prepared! <======================================
WSGI app 0 (mountpoint='/flask/test') ready in 0 seconds ...
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 1212)
spawned uWSGI worker 1 (pid: 1216, cores: 1)
spawned uWSGI worker 2 (pid: 1217, cores: 1)
spawned uWSGI worker 3 (pid: 1218, cores: 1)
spawned uWSGI worker 4 (pid: 1219, cores: 1)

因此,在这个简化的示例中,uwsgi 生成了 4 个 worker,但只执行了一次 do_some_preparation()。在实际应用中,打开了几个数据库连接,显然这些连接被这4个进程重用并导致并发请求问题。

有没有办法告诉 uwsgi 产生几个完全独立的进程?

编辑:当然,我可以使用以下解决方法:

from flask import Flask, Response
app = Flask(__name__)

all_prepared = False

def do_some_preparation():
    global all_prepared
    all_prepared = True
    print("Prepared!")


@app.route("/test")
def get_test():
    if not all_prepared:
        do_some_preparation()
    return Response("test")

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

但是我将不得不在每条路线中都放置这个“all_prepared”检查,这似乎不是一个好的解决方案。

【问题讨论】:

    标签: flask uwsgi


    【解决方案1】:

    默认情况下,uWSGI 会进行预分叉。因此,您的应用会被加载一次,然后分叉。

    如果您想为每个工作人员加载一次应用,请将 --lazy-apps 添加到 uWSGI 选项中。

    顺便说一下,在这两种情况下,您都处于真正的多处理状态:)

    【讨论】:

    • 当lazy apps = true 时,请求似乎需要更多时间,这是否正常?
    • 任何人都可以确认,延迟应用程序的请求速度较慢(工作人员的第一个请求除外)?如果是,我想了解
    【解决方案2】:

    看来我自己找到了答案。答案是:我的代码应该被重新设计为:

    @app.before_first_request
    def do_some_preparation():
        ...
    

    然后 Flask 将负责为每个工作人员分别运行 do_some_preparation() 函数,允许每个工作人员拥有自己的数据库连接(或其他并发不容忍资源)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-25
      • 2020-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-04
      • 2021-07-26
      • 2012-09-30
      相关资源
      最近更新 更多