Werkzeug 和 class 与 Flask 的状态:当 class 没有被重新初始化时,class 成员变量如何重置?
Werkzeug and class state with Flask: How are class member variables resetting when the class isn't being reinitialized?
我正在尝试编写一个烧瓶扩展,需要在请求之间保留一些信息。当我 运行 Werkzeug 使用单个进程时,这工作正常,但是当我 运行 使用多个进程时,我得到一些我不理解的奇怪行为。以这个简单的应用为例:
from flask import Flask
app = Flask(__name__)
class Counter(object):
def __init__(self, app):
print('initializing a Counter object')
self.app = app
self.value = 0
def increment(self):
self.value += 1
print('Just incremented, current value is ', self.value)
counter = Counter(app)
@app.route('/')
def index():
for i in range(4):
counter.increment()
return 'index'
if __name__ == '__main__':
#scenario 1 - single process
#app.run()
#scenario 2 - threaded
#app.run(threaded=True)
#scenario 3 - two processes
app.run(processes=2)
对于前两个场景,它的行为完全符合我的预期:Counter 对象被初始化一次,然后随着对“/”路由的每个请求而递增。当我 运行 它与第三种情况(传递进程=2)然后我得到这个作为输出:
initializing a Counter object
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Just incremented, current value is 1
Just incremented, current value is 2
Just incremented, current value is 3
Just incremented, current value is 4
127.0.0.1 - - [30/Aug/2015 09:47:25] "GET / HTTP/1.1" 200 -
Just incremented, current value is 1
Just incremented, current value is 2
Just incremented, current value is 3
Just incremented, current value is 4
127.0.0.1 - - [30/Aug/2015 09:47:26] "GET / HTTP/1.1" 200 -
Just incremented, current value is 1
Just incremented, current value is 2
Just incremented, current value is 3
Just incremented, current value is 4
127.0.0.1 - - [30/Aug/2015 09:47:27] "GET / HTTP/1.1" 200 -
似乎 counter.value 在初始化后立即返回到它的状态,而实际上并未重新初始化。有人可以阐明 Werkzeug 在内部为实现这一目标所做的工作吗?我也很想知道是否有办法让这个行为像我天真地期望的那样(两个进程,每个进程都有自己的 Counter 实例)。谢谢!
第一个示例(单线程)只使用了Counter
,所以它有效。
第二个例子(多线程),生成线程来处理每个请求。它们与在它们生成之前创建的 Counter
共享内存,因此每次递增它们都会产生相同的结果。
最后一个例子(多进程),产生进程来处理每个请求。 Flask's dev server uses fork
: each child sees the same starting point (counter is already initialized) but increments in their own address space 请求结束时消失。
import os
class Counter:
def __init__(self):
print('init')
self.value = 0
def increment(self):
self.value += 1
print('inc -> {}'.format(self.value))
counter = Counter()
def multi():
if not os.fork():
# child starts with copy of parent memory
for _ in range(3):
# increments three times
counter.increment()
# child is done
os._exit(0)
# three processes run
for _ in range(3):
multi()
init
inc -> 1
inc -> 2
inc -> 3
inc -> 1
inc -> 2
inc -> 3
inc -> 1
inc -> 2
inc -> 3
使用数据库或其他外部存储跨进程存储全局状态,使用 before_
和 after_request
。请注意,这并不完全简单,因为您必须以线程安全的方式存储每个请求的计数器增量值,这样两个线程就不会同时覆盖该值。
req 1 starts, gets stored value = 4
req 2 starts, gets stored value = 4
req 1 increments, value = 8
req 1 saves, value = 8
req 2 increments, value = 8
req 2 saves, value = 8 but should = 12
我正在尝试编写一个烧瓶扩展,需要在请求之间保留一些信息。当我 运行 Werkzeug 使用单个进程时,这工作正常,但是当我 运行 使用多个进程时,我得到一些我不理解的奇怪行为。以这个简单的应用为例:
from flask import Flask
app = Flask(__name__)
class Counter(object):
def __init__(self, app):
print('initializing a Counter object')
self.app = app
self.value = 0
def increment(self):
self.value += 1
print('Just incremented, current value is ', self.value)
counter = Counter(app)
@app.route('/')
def index():
for i in range(4):
counter.increment()
return 'index'
if __name__ == '__main__':
#scenario 1 - single process
#app.run()
#scenario 2 - threaded
#app.run(threaded=True)
#scenario 3 - two processes
app.run(processes=2)
对于前两个场景,它的行为完全符合我的预期:Counter 对象被初始化一次,然后随着对“/”路由的每个请求而递增。当我 运行 它与第三种情况(传递进程=2)然后我得到这个作为输出:
initializing a Counter object
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Just incremented, current value is 1
Just incremented, current value is 2
Just incremented, current value is 3
Just incremented, current value is 4
127.0.0.1 - - [30/Aug/2015 09:47:25] "GET / HTTP/1.1" 200 -
Just incremented, current value is 1
Just incremented, current value is 2
Just incremented, current value is 3
Just incremented, current value is 4
127.0.0.1 - - [30/Aug/2015 09:47:26] "GET / HTTP/1.1" 200 -
Just incremented, current value is 1
Just incremented, current value is 2
Just incremented, current value is 3
Just incremented, current value is 4
127.0.0.1 - - [30/Aug/2015 09:47:27] "GET / HTTP/1.1" 200 -
似乎 counter.value 在初始化后立即返回到它的状态,而实际上并未重新初始化。有人可以阐明 Werkzeug 在内部为实现这一目标所做的工作吗?我也很想知道是否有办法让这个行为像我天真地期望的那样(两个进程,每个进程都有自己的 Counter 实例)。谢谢!
第一个示例(单线程)只使用了Counter
,所以它有效。
第二个例子(多线程),生成线程来处理每个请求。它们与在它们生成之前创建的 Counter
共享内存,因此每次递增它们都会产生相同的结果。
最后一个例子(多进程),产生进程来处理每个请求。 Flask's dev server uses fork
: each child sees the same starting point (counter is already initialized) but increments in their own address space 请求结束时消失。
import os
class Counter:
def __init__(self):
print('init')
self.value = 0
def increment(self):
self.value += 1
print('inc -> {}'.format(self.value))
counter = Counter()
def multi():
if not os.fork():
# child starts with copy of parent memory
for _ in range(3):
# increments three times
counter.increment()
# child is done
os._exit(0)
# three processes run
for _ in range(3):
multi()
init
inc -> 1
inc -> 2
inc -> 3
inc -> 1
inc -> 2
inc -> 3
inc -> 1
inc -> 2
inc -> 3
使用数据库或其他外部存储跨进程存储全局状态,使用 before_
和 after_request
。请注意,这并不完全简单,因为您必须以线程安全的方式存储每个请求的计数器增量值,这样两个线程就不会同时覆盖该值。
req 1 starts, gets stored value = 4
req 2 starts, gets stored value = 4
req 1 increments, value = 8
req 1 saves, value = 8
req 2 increments, value = 8
req 2 saves, value = 8 but should = 12