最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【规避解决】Flask中开了多个worker时如何使用全局变量

Flask crifan 11299浏览 0评论

Flask的app,去用gunicorn启动,很自然的参考别处的写法,设置了4个worker:

同时,为了实现websocket,添加了

-k flask_sockets.worker

然后用supervisor去管理,配置如下:

/Users/crifan/dev/dev_root/daryun/Projects/RunningFast/sourcecode/RunningFast-Server/supervisor.conf

command=/root/Envs/RunningFast/bin/gunicorn -w 4 -b 0.0.0.0:21085 -k flask_sockets.worker run:app &

此处,Flask内部使用了:

全局变量,用于保存当前有效的websocket的连接

gWsDict = {}

但是现象出了问题:

对于之前保存了的变量值:

added new ws for user user-cc680b0a-8d04-4f2b-8ad9-c6fefb527861 , gWsDict={u’user-cc680b0a-8d04-4f2b-8ad9-c6fefb527861′: <geventwebsocket.websocket.WebSocket object at 0x7f3a36749e50>}

但是后来别的请求中,却获取不到:

DEBUG in Websocket [/root/RunningFast/staging/runningfast/resources/Websocket.py:138]:
gWsDict={}

-》

之前也遇到了,类似现象,但是已经解决了:

【已解决】Flask中的全局变量的值获取不到

其中也提到了:

由于多线程,会导致不同线程内部,其实有自己的独立的全局变量区域

-》Flask多个线程中,各自有自己不同的全局变量

-》别的线程中,全局变量赋值了,但是另外的线程中的该全局变量还是没有值

-》可能要涉及到进程,线程,数据同步的问题

去看看:

Understanding Contexts in Flask

python – Preserving global state in a flask application – Stack Overflow

python – Flask global variables – Stack Overflow

-》

flask.g是基于每个request来说的,全局

Flask的app,可能运行在多个进程(中的多个线程)

-》说解决办法就是:

不要用这种全局变量

改用数据库(或者其他方式,比如缓存)去存储

flask how store  global value

python – How to share the global app object in flask? – Stack Overflow

[ASK Flask] Application wide variable:flask

和我的需求一样,

提到了用:

memcached

redis

-》此处借用我的,之前已经正在使用的redis?

flask redis store global value

python – Inconsistent globals in Flask – Stack Overflow

->也是推荐用redis

Flask-Cache — Flask-Cache 0.13 documentation

-》

好像是可以通过:

Flask-Cache去保存全局的变量(对象)的

flask-cache store global value

flask-cache 保存 全局变量

Using Flask Cache | python | flask | BrunoRocha.org | Python web development

-》

Caching arbitrary objects

from cache import cache
def function():
    cached = cache.get(‘a_key’)
    if cached:
        return cached
    result = do_some_stuff()
    cache.set(‘a_key’, result, timeout=300)
    return result

Memoized? · Issue #16 · thadeusb/flask-cache

缓存 — Flask 中文手册 0.10 文档

-》

直接使用Flask中的Werkzeug自带的cache

好像就不用额外安装Flask-Cache了?

然后发现可以考虑:

之前就想到的方案

把此处的dict对象变量,用pickle序列化为字符串后,存到redis中,

读取时再反序列化为对象

就可以了?

搜:

python redis store object

参考:

python – how to store a complex object in redis (using redis-py) – Stack Overflow

import pickle
import redis
r = redis.StrictRedis(host=’localhost’, port=6379, db=0)
obj = ExampleObject()
pickled_object = pickle.dumps(obj)
r.set(‘some_key’, pickled_object)
unpacked_object = pickle.loads(r.get(‘some_key’))
obj == unpacked_object

不过有说:

反序列化时可以执行任意代码-》不够安全

-》JSON方案更安全

import json
import redis
r = redis.StrictRedis(host=’localhost’, port=6379, db=0)
images= [
    {‘type’:’big’, ‘url’:’….’},
    {‘type’:’big’, ‘url’:’….’},
    {‘type’:’big’, ‘url’:’….’},
]
json_images = json.dumps(images)
r.set(‘images’, json_images)
unpacked_images = json.loads(r.get(‘images’))
# python3:
# unpacked_images = json.loads(r.get(‘images’).decode(‘utf-8’))
images == unpacked_images

python – get object from redis without eval? – Stack Overflow

def set_value(redis, key, value):
    redis.set(key, pickle.dumps(value))
def get_value(redis, key):
    pickled_value = redis.get(key)
    if pickled_value is None:
        return None
    return pickle.loads(pickled_value)

搜:

json.dumps 对象

序列化 – 廖雪峰的官方网站

“变量的内容又回来了!

当然,这个变量和原来的变量是完全不相干的对象,它们只是内容相同而已。”

-》这样还是无法实时保存对应的变量啊。。。

-》因为我内部要去获取对应dict中的websocket对象,然后去用websocket去发送消息的。。。

6.2 读写JSON数据 — python3-cookbook 2.0.0 文档

Python实现支持JSON存储和解析的对象 – Adan – 博客频道 – CSDN.NET

【无法解决】Flask中用pickle去保存Websocket对象出错:TypeError a class that defines __slots__ without defining __getstate__ cannot be pickled

【总结】

最后实在不行了。

暂时先把gunicorn的worker设置为1:

/Users/crifan/dev/dev_root/daryun/Projects/RunningFast/sourcecode/RunningFast-Server/supervisor.conf

[program:runningfast_stable]
directory=/root/RunningFast/stable
command=/root/Envs/RunningFast/bin/gunicorn -w 1 -b 0.0.0.0:21084 -k flask_sockets.worker run:app &
[program:runningfast_staging]
directory=/root/RunningFast/staging
command=/root/Envs/RunningFast/bin/gunicorn -w 1 -b 0.0.0.0:21085 -k flask_sockets.worker run:app &

然后继续使用全局变量的方案,暂时就可以先保证可以通过全局变量获得对应的webscoket的示例对象了。

-》等以后找到更好的办法,再说。

【后记】

后来,是避开了 全局变量的方法,而用:

【已解决】Flask中的线程或进程间通信

去解决了,此处的,实时的对象,的传递和处理的问题。

转载请注明:在路上 » 【规避解决】Flask中开了多个worker时如何使用全局变量

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
82 queries in 0.192 seconds, using 22.10MB memory