9

I am trying to find out how to work with global variables in Flask:

gl = {'name': 'Default'}

@app.route('/store/<name>')
def store_var(name=None):
    gl['name'] = name
    return "Storing " + gl['name']

@app.route("/retrieve")
def retrieve_var():
    n = gl['name']
    return "Retrieved: " + n

Storing the name and retrieving it from another client works fine. However, this doesn't feel right: a simple global dictionary where any session pretty much simultaneously can throw in complex objects, does that really work without any dire consequences?

Passiday
  • 7,573
  • 8
  • 42
  • 61
  • 3
    Checkout Redis it provides distributed thread safe data structures for just this purpose. Keep in mind that this will also fail if you are running many load balanced python processes. If a request gets directed to a different process its going to have different values stored in its local dictionary. – nsfyn55 May 05 '14 at 15:54

1 Answers1

17

No, it doesn't work, not outside the simple Flask development server.

WSGI servers scale in two ways; by using threads or by forking the process. A global dictionary is not a thread-safe storage, and when using multi-processing changes to globals are not going to be shared. If you run this on a PAAS provider like Google App Server, the processes aren't even forked; they are run on entirely separate machines even.

Use some kind of backend storage instead; a memcached server, a database server, something to control concurrent access and share the data across processes.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • If the gl was declared in a module 'foo.py' which is then imported in the above code using 'import foo', and then if user used foo.gl to set and get the value, then would it be good solution? – variable Nov 01 '19 at 09:29
  • @variable: no, that's no different from using the same dictionary from within the `foo` module. Importing a dictionary from another module doesn't change the nature of the dictionary or protect you from concurrency issues. – Martijn Pieters Nov 01 '19 at 10:49
  • Ok. For each request, for example (/retrieve), does the function (retrieve_var) run in a new stack frame in a new thread? So when the thread runs, the OP's code is setting 'name' key to value 'default'. Hence the /retrieve will always return 'Default' - am I right? – variable Nov 01 '19 at 10:57
  • Or does the new thread only run the function and still has access to globals modified by previous url requests (although not thread safe)? – variable Nov 01 '19 at 11:04
  • @variable: this is getting to be quite broad and a general concurrency discussion. 'stack frames' have nothing to do with concurrency really, stack frames are created whenever you call a Python function, regardless of threading. **Within a single process** all threads have access to the same globals. If requests are being handled by multiple processes (on a single machine or on multiple), then different processes have different globals. – Martijn Pieters Nov 01 '19 at 11:09
  • Are class variables also globals across threads in the same process? Example: If one thread sets class variable to 100 then do instances in all threads get this value? – variable Nov 01 '19 at 11:26
  • @variable: class attributes are no different from globals; they are just namespaced to a class object. – Martijn Pieters Nov 01 '19 at 18:16
  • If I install a package via pip install xyz. Then, import xyz in route.py. Then, in the route fucntion if I assign or mutate a variable in xyz, via xyz.varname.append or xyz.varname=100. Now, this will affect varname in all other user threads? This is very dangerous then isnt it? Please correct me if I'm wrong. Thanks – variable Nov 02 '19 at 14:18
  • @variable: you are going over the same ground again and again here. All Python modules act the same. – Martijn Pieters Nov 02 '19 at 14:38