-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pyglet fails to render from multiple threads #50
Comments
hmm I get a slightly different error on MacOS, but irrespective it looks like pyglet is not thread safe. In the interest of supporting |
OpenCV is the obvious choice as it's already in the dependency tree for the resizing wrapper. I found some basic code here for working with video streams that can probably be adapted pretty easily: https://solarianprogrammer.com/2018/04/21/python-opencv-show-video-tkinter-window/ |
I haven't consulted the source, but are you sure the problem is not with sharing some pyglet stuff between environments that would better be kept individually for each? I suspect, after some googling, that pyglet, and OpenGL in general, needs a separate rendering context for each thread, and one may have to explicitly switch context before rendering (which may be an expensive operation). Hm. Maybe it would hurt single-threaded multi-window performance if more "individual property" were introduced. On the other hand, maybe some GL window libraries sort this out as needed, depending on threads etc. I shall also try an experiment with multiple windows in a single thread, to be able to draw conclusions on whether threading is the relevant issue here. At least we know that multiprocessing works as intended. |
looks like the opencv solution isn't viable. It looks bad in single threaded mode and hangs indefinitely running the script you provided. I can't seem to find a better render solution at the moment. fortunately this only seems to affect python threads. |
Hi @EliasHasle , have you managed to resolve this? |
@michele-arrival to the best of my knowledge, the issue still exists. I've updated the bug script to show the issue with multiprocessing as well: import threading
import multiprocessing
import gym_super_mario_bros
from gym_super_mario_bros.actions import COMPLEX_MOVEMENT
from nes_py.wrappers import JoypadSpace
RENDER = True
MULTIPROCESS = False
THREADS = 2
def testEnv():
env = gym_super_mario_bros.make('SuperMarioBros-v0')
env = JoypadSpace(env, COMPLEX_MOVEMENT)
done = True
for _ in range(5000):
if done:
env.reset()
_, _, done, _ = env.step(env.action_space.sample())
if RENDER:
env.render()
return True
threads = [None] * THREADS
for i in range(THREADS):
if MULTIPROCESS:
threads[i] = multiprocessing.Process(target=testEnv)
else:
threads[i] = threading.Thread(target=testEnv)
threads[i].start()
for t in threads:
t.join() |
Multiprocessing will work, but nes-py has to be imported within the process that executes the OpenGL context: import threading
import multiprocessing
RENDER = True
MULTIPROCESS = True
THREADS = 2
def testEnv():
import gym_super_mario_bros
from gym_super_mario_bros.actions import COMPLEX_MOVEMENT
from nes_py.wrappers import JoypadSpace
env = gym_super_mario_bros.make('SuperMarioBros-v0')
env = JoypadSpace(env, COMPLEX_MOVEMENT)
done = True
for _ in range(5000):
if done:
env.reset()
_, _, done, _ = env.step(env.action_space.sample())
if RENDER:
env.render()
return True
threads = [None] * THREADS
for i in range(THREADS):
if MULTIPROCESS:
threads[i] = multiprocessing.Process(target=testEnv)
else:
threads[i] = threading.Thread(target=testEnv)
threads[i].start()
for t in threads:
t.join() Because of how OpenGL works, python threads will not work without some form of special support that would needlessly complicate the render logic in nes-py. In most cases, multiprocessing is a better option for concurrency because it provides true process level concurrency, opposed to python-level threads. I've added some logic to detect rendering from python threads and fail gracefully with a RuntimeError. |
Thanks for the update! |
So in other words what would be the fix for this? |
Describe the bug
Calling render from a new thread after first calling it from another results in an error (see console output below). This may well be a limitation of Pyglet, but I don't know. Note that running the environments without rendering to screen works as expected, but for some purposes (debugging of graphical glitches etc.) it can be very useful to monitor multiple environments at the same time, even if they are in different threads.
If Pyglet is the problem, maybe one of the alternatives works better?
To Reproduce
Expected behavior
Rendering in independent windows.
Environment
Additional context
The text was updated successfully, but these errors were encountered: