在Flask(WSGI)中使用全局单例,我是否必须担心竞争条件?

But*_*840 19 python wsgi thread-safety race-condition flask

Flask的hello world演示是:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()
Run Code Online (Sandbox Code Playgroud)

如果我这样修改了怎么办:

from flask import Flask
app = Flask(__name__)

a = 1
b = 2
c = 3

@app.route("/")
def hello():
    a += 1
    b += a
    c += b
    return "Hello World!"

if __name__ == "__main__":
    app.run()
Run Code Online (Sandbox Code Playgroud)

我理解WSGI应用程序可能有多个线程.该hello函数可以同时在多个线程上运行,然后我们就会遇到竞争条件.它是否正确?如果上面的代码不是线程安全的,我该怎么做才能使它的线程安全?

避免全局变量是一种可能的解决方案,但是你总能避免使用全局变量吗?如果我想要类似python对象缓存的内容怎么办?

Mar*_*ech 11

你可以使用锁:

from threading import Lock
from flask import Flask
app = Flask(__name__)

a = 1
b = 2
c = 3
lock = Lock()

@app.route("/")
def hello():
    with lock:
        a += 1
        b += a
        c += b
    return "Hello World!"

if __name__ == "__main__":
    app.run()
Run Code Online (Sandbox Code Playgroud)

  • 您的示例(完全剪切并粘贴)会为我返回500,因为a在分配之前被引用. (3认同)

小智 6

您可以尝试 werkzeug 的 Local 课程。以下是有关它的一些信息:Context Locals

例子:

from flask import Flask
from werkzeug.local import Local
app = Flask(__name__)
loc = Local()
loc.a = 1
loc.b = 2
loc.c = 3

@app.route("/")
def hello():
    loc.a += 1
    loc.b += loc.a
    loc.c += loc.b
    return "Hello World!"

if __name__ == "__main__":
    app.run()
Run Code Online (Sandbox Code Playgroud)


小智 -1

您可能会看一下g可以直接从 Flask 导入的对象,为该请求全局保留一个对象。如果您使用事件驱动的 WSGI 服务器(tornado、gevent 等),那么您应该不会遇到任何问题。

  • 我认为“g”对象仅在请求期间保持状态,因此对于上述用例没有用处。 (8认同)