I am trying to figure out how to have a global variable that isn’t overwritten by Streamlit on page refresh. From How to use global variable in streamlib? - #2 by ferdy, it seems session_state is the only way to accomplish this.
So my question is, how can one have a global variable in a Python script, outside of session_state, that isn’t overwritten upon refreshing Streamlit?
I guess one solution is using something entirely outside of a Python process, like the OS filesystem, reading/writing from a file. Basically, Socket.IO events write to the file, Streamlit reads from the file.
Anything in a module other than your main script won’t be overwritten by reruns or refreshes. So just put the queue in a separate module
Here is an example monkey-patching streamlit (not that I recommend it, but it makes it easier to demonstrate). The queue will will be shared across sessions and it will maintain its state through reruns and refreshes. The usual caveats about sharing mutable global state in multi-threading code apply. Appending to and popping from a deque are safe operations according to the docs.
import streamlit as st
from collections import deque
if not hasattr(st, "app_queue"):
st.app_queue = deque()
element = st.text_input("Value")
if st.button("Add to app queue"):
st.app_queue.append(element)
st.info(f"\"{element}\" added to the queue.")
if st.button("Pop from app queue"):
try:
element = st.app_queue.popleft()
except IndexError:
st.error("Queue is empty.")
else:
st.info(f"\"{element}\" popped from the queue.")
I just realized that the idiomatic way of having app-level mutable state in streamlit apps is using st.cache_resource.
import streamlit as st
from collections import deque
@st.cache_resource
def get_app_queue():
return deque()
app_queue = get_app_queue()
element = st.text_input("Value")
if st.button("Add to app queue"):
app_queue.append(element)
st.info(f"\"{element}\" added to the queue.")
if st.button("Pop from app queue"):
try:
element = app_queue.popleft()
except IndexError:
st.error("Queue is empty.")
else:
st.info(f"\"{element}\" popped from the queue.")
I learned (not from the docs but from a post in the forum that I cannot find right now) that each instance of a streamlit app runs in a single process. Each session runs in a separate thread of the same process.
So reruns and refreshes just kill and create threads, but module-level variables are not affected by it.
I have seen messages like these reported before, but I have little experience with multithreadng, specially in streamlit apps. There is this open issue that might help:
Thanks for stopping by! We use cookies to help us understand how you interact with our website.
By clicking “Accept all”, you consent to our use of cookies. For more information, please see our privacy policy.
Cookie settings
Strictly necessary cookies
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
Performance cookies
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
Functional cookies
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
Targeting cookies
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.