Created
March 27, 2021 01:32
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""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() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""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