Iva*_*nna 6 python werkzeug multiple-processes flask
我正在尝试编写一个烧瓶扩展,需要在请求之间保留一些信息.当我使用单个进程运行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)
Run Code Online (Sandbox Code Playgroud)
对于前两个场景,它的行为完全符合我的预期: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 -
Run Code Online (Sandbox Code Playgroud)
似乎counter.value在初始化之后立即返回到它的状态而没有实际重新初始化.有人可以了解Werkzeug在内部做些什么来实现这一目标吗?我也非常有兴趣学习是否有办法使这个行为像我天真期望的那样(两个进程,每个进程都有自己的Counter实例).谢谢!
第一个示例(单线程)仅使用 one Counter,因此它可以工作。
第二个示例(多个线程),生成线程来处理每个请求。Counter它们与在生成之前创建的内存共享内存,因此从每个增量中增加它们会产生相同的结果。
最后一个示例(多个进程),生成进程来处理每个请求。 Flask 的开发服务器使用fork:每个子进程看到相同的起始点(计数器已经初始化),但在自己的地址空间中递增,当请求结束时,该地址空间就会消失。
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()
Run Code Online (Sandbox Code Playgroud)
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()
Run Code Online (Sandbox Code Playgroud)
使用数据库或其他外部存储来存储跨进程的全局状态,使用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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
507 次 |
| 最近记录: |