Created
March 14, 2025 17:42
-
-
Save dhdaines/574d58eed7da9c459e3ef2b50a3ac27b to your computer and use it in GitHub Desktop.
Running asyncio tasks in a separate thread under streamlit
This file contains 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
import asyncio | |
import threading | |
from concurrent import futures | |
import streamlit as st | |
def create_async_loop(): | |
print("CREATE_ASYNC_LOOP START") | |
loop = asyncio.new_event_loop() | |
st.session_state.event_loop = loop | |
done = asyncio.Event() | |
st.session_state.event_loop_done = done | |
async def loop_main(): | |
print("LOOP_MAIN START") | |
await done.wait() | |
print("LOOP_MAIN STOP") | |
def thread_main(): | |
print("THREAD_MAIN START") | |
loop.run_until_complete(loop_main()) | |
print("THREAD_MAIN STOP") | |
loop_runner = threading.Thread(target=thread_main) | |
st.session_state.event_loop_runner = loop_runner | |
st.runtime.scriptrunner.add_script_run_ctx( | |
loop_runner, st.runtime.scriptrunner.get_script_run_ctx() | |
) | |
loop_runner.start() | |
print("CREATE_ASYNC_LOOP DONE") | |
def stop_async_loop(): | |
print("STOP_ASYNC_LOOP START") | |
st.session_state.event_loop.call_soon_threadsafe( | |
st.session_state.event_loop_done.set | |
) | |
st.session_state.event_loop_runner.join() | |
del st.session_state.event_loop | |
del st.session_state.event_loop_runner | |
del st.session_state.event_loop_done | |
print("STOP_ASYNC_LOOP DONE") | |
if "event_loop" not in st.session_state: | |
create_async_loop() | |
async def do_nothing(): | |
print("DO_NOTHING START") | |
await asyncio.sleep(3) | |
print("DO_NOTHING DONE") | |
if "tasks" not in st.session_state: | |
st.session_state.tasks = [] | |
if st.button(label="Do something"): | |
f = asyncio.run_coroutine_threadsafe(do_nothing(), st.session_state.event_loop) | |
st.session_state.tasks.append(f) | |
if st.button(label="Do something else"): | |
st.toast("Hello!") | |
if st.button(label="Stop"): | |
stop_async_loop() | |
for t in st.session_state.tasks: | |
t.cancel() | |
taskbox = st.empty() | |
while st.session_state.tasks: | |
st.session_state.tasks = [t for t in st.session_state.tasks if not t.done()] | |
taskbox.write(st.session_state.tasks) | |
futures.wait(st.session_state.tasks, timeout=1) | |
taskbox.write(st.session_state.tasks) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment