Skip to content

Instantly share code, notes, and snippets.

@michaelwooley
Created March 27, 2021 01:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save michaelwooley/d459bbc9cc0dbb1c34d4573a2a339c63 to your computer and use it in GitHub Desktop.
Save michaelwooley/d459bbc9cc0dbb1c34d4573a2a339c63 to your computer and use it in GitHub Desktop.
Demos of how global variables play out when you're running python on multiple threads.
"""Demo behavior of global variables across threads.
"""
from threading import Thread
import time
shared_var = "outside" # global variable
def thread1(threadname: str) -> None:
global shared_var
for _ in range(5):
time.sleep(0.25)
print(f"From {threadname}: shared_var = {shared_var} | {shared_var == threadname}")
shared_var = threadname
def thread2(threadname: str) -> None:
global shared_var
for _ in range(5):
shared_var = threadname
time.sleep(0.25)
print(f"From {threadname}: shared_var = {shared_var} | {shared_var == threadname}")
def main() -> None:
thread_fn1 = Thread(target=thread1, args=("A",))
thread_fn2 = Thread(target=thread2, args=("B",))
thread_fn1.start()
thread_fn2.start()
thread_fn1.join()
thread_fn2.join()
if __name__ == "__main__":
main()
"""Demo of different methods for maintaining a global context in a flask app.
---
Run the app:
```
gunicorn --reload -k gevent -b '0.0.0.0:3005' scratch.leaked_context.leaked_context_app:app
```
Now make requests:
```
import requests
url = "http://0.0.0.0:3005/"
requests.get(url, json={"name": "A", "seconds": 5}) # In one console
requests.get(url, json={"name": "B", "seconds": 1}) # In another
```
"""
import json
import logging
import time
from flask import Flask, g, jsonify, request
from werkzeug.local import get_ident, Local # type: ignore
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = Flask(__name__)
SHARED_GLOBAL = "[unset]"
SHARED_LOCAL = Local()
get_thread_name = lambda: hex(id(get_ident()))
@app.route("/")
def my_route():
global SHARED_GLOBAL
body = json.loads(request.get_data(as_text=True)) # request.get_json() or json.loads
seconds = body.get("seconds", 1)
name = body.get("name", "[name]")
g.name = name # This will work
SHARED_LOCAL = name # This will work
SHARED_GLOBAL = name # This will not
poll_context = 0.5
tot_sec = 0
while tot_sec <= seconds:
# Logging info is interesting to check out (-vvs)
msg = f"""
{name} @ {tot_sec} out of {seconds}. Thread = {get_thread_name()}"""
for nm, v in [("g", g.name), ("Local", SHARED_LOCAL), ("global", SHARED_GLOBAL)]:
_is_same = v == name
msg += f"""
({name}) {nm:8s} {v} | name correct? {_is_same}"""
logger.info(msg)
time.sleep(poll_context)
tot_sec += poll_context
return jsonify({})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment