Closed cyberic99 closed 1 year ago
Hi, under the hood Jupylet and the App object employ Python's async programming. It is a programming paradigm that is not entirely compatible with threading.
You may run code and functionality in Python threads, but the App object itself needs an async event loop and I believe this should be done in the main program thread.
The reason for this design choice is that Jupyter notebooks are asynchronous and Jupylet was designed to fit in.
See here for more info:
https://docs.python.org/3/library/asyncio.html https://realpython.com/async-io-python/
Thanks for reporting!
Hi, I've read the documentation you provided, thank you.
However, I still cannot run the app
in a separate thread.
I tried to call asyncio.run_coroutine_threadsafe(app.run(), loop)
, but the render()
function seems to be called only once.
Do I need to start the app somehow?
Here are the logs:
2021-06-23 18:28:02,888 - jupylet.event - INFO - Enter EventLeg.event(*args=(<function create_app.<locals>.key_event at 0x7f94687f70d0>,)).
2021-06-23 18:28:02,889 - jupylet.clock - INFO - Enter ClockLeg.schedule_interval(interval=0.041666666666666664, **kwargs={}).
2021-06-23 18:28:02,889 - jupylet.clock - INFO - Enter Scheduler.schedule_interval(foo=<function create_app.<locals>.modify_volume at 0x7f94687f71f0>, interval=0.041666666666666664, **kwargs={}).
2021-06-23 18:28:02,975 - jupylet.event - INFO - Enter EventLeg.event(*args=(<function create_app.<locals>.render at 0x7f94687f7310>,)).
Thanks
It seems it should be possible to start an event loop in another thread. If you can do that, the app object should run in that "side" thread:
https://docs.python.org/3/library/asyncio-dev.html#concurrency-and-multithreading
Thanks, I tried use asyncio
in a thread, I can see the window but it stays black
import time
from jupylet.app import App
from threading import Thread
import logging
import asyncio
import sys
if __name__ == '__main__':
def new_app():
from jupylet.shadertoy import Shadertoy
app = App(width=512, height=512, quality=100, mode="auto", log_level=logging.INFO)
st = Shadertoy("""
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.xy;
vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
fragColor = vec4(col,1.0);
}
""")
@app.event
def render(ct, dt):
app.window.clear()
st.draw(ct, dt)
return app
# in main thread, this works:
# app = new_app()
# app.run()
# this doesn't work: the window is there but stays black
def start_loop(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
print("exiting thread")
app = new_app()
app_loop = asyncio.new_event_loop()
t = Thread(target=start_loop, args=(app_loop,), daemon=True)
t.start()
app_loop.call_soon(app.run)
time.sleep(3)
sys.exit(0)
Just a small update, I have successfully run the app like this:
from jupylet.clock import setup_fake_time
app = new_app()
app.mode = "hidden"
app.fake_time=setup_fake_time()
app.start()
while True:
time.sleep(0.1)
app.step()
It is a bit hackish but it works and I can see he result on screen.
I could also do that in hidden
mode:
app = new_app()
app.start()
while True:
time.sleep(0.1)
app.step()
print(app.observe())
unfortunately, I'd like to use another (Panda3D) OpenGL app at the same time, and I don't think it's possible
But at least this issue is solved now.
Thank you for your support.
Hi,
I'd like to run an (headless) App in a separate thread.
I'd like to render some shaders, and use the framebuffer into another part of my application.
I tried this simple code:
but I get this error:
I also tried to use
mode="auto"
andapp.run()
, but I get:Is there a way to call a render iteration x times per second, or in a separate thread?
Thank you