Details
-
Suggestion
-
Resolution: Won't Do
-
Not Evaluated
-
None
-
5.15.2, 6.2.2
-
None
Description
Hello, I'm facing a probleme related to 1176 and 803
the overriden methods of my widgets are calling the super-class methods, but those do not allow threads despite being in native C++. Thus my background tasks as completely slowed down each time the native method is slow (performing rendering for instance).
description of the problem
What I'm doing is quite simple, working on a 3D view I have a widget doing rendering and navigation.
Here is my initial implementation (which works well for everything but multithreading)
# a widget class, doing rendering, and handling view navigation events class SceneView(QOpenGLWidget): def __init__(self, ...): super().__init__(parent) ... # override event in order to get touchscreen events, mouse events, keyboard events ... all in the same callback def event(self, evt): if isinstance(evt, InputEvent): self.inputEvent(evt) if evt.isAccepted(): return True # call base class event handler # it will take care of any other events, like resizing, rendering, ... return super().event(evt) # and this doesn't release the GIL, even while rendering def paintGL(self): self.makeCurrent() self.render() def render(self): # many openGL calls # !! but no wait for openGL task termination: this method is very fast then ...
This works great until we need a thread performing anything frequently (either computations, but io tasks as well !) In my specific case, the background task is a socket communication
my background thread has a loop that loops:
- every 0.05s as planned when no Qt app is running
- every 0.05s as planned when a Qt app is running with the SceneView idling
- every 1s due to Qt slowing down, when the SceneView is frequently updated (a mouse movement for instance)
So I agree, with the conclusion of 803 that most method should no release the GIL to keep up the GUI's performances, but the methods that are going to run for a while definitely should (in my case, QOpenGLWidget.event should)
Here is the complete implementation of the widget: pymadcad/rendering
Temporary fix
There is a workaround for my specific case: having a different widget for receiving the events than for rendering. So we will not override the event method responsible for rendering.
However this is more a trick than a solution: I'm obliged to create an invisible widget just to deal with event dispatching behaviors. Also It won't solve an issue with a slow method doing something else than rendering ...
# a widget class, doing only rendering class SceneView(QOpenGLWidget): def __init__(self, ...): super().__init__(parent) ... self.handler = EmptyWidget(self) # ugly trick: place an invisible widget to receive input events instead # NOTE: the base-class event() function is not overriden, so it does not hold the GIL, and other threads can live def resizeEvent(self, evt): self.handler.resize(self.size()) def paintGL(self): self.makeCurrent() self.render() def render(self): # many openGL calls # !! but no wait for openGL task termination, so to call this method is very fast ... # an invisible widget class EmptyWidget(QWidget): def __init__(self, parent): super().__init__(parent) # override event in order to get touchscreen events, mouse events, keyboard events ... all in the same callback # but this widget renders nothing, so to call it is very fast def event(self, evt): if isinstance(evt, InputEvent): self.parent().inputEvent(evt) # ugly trick: transmit events to the scene view if evt.isAccepted(): return True return super().event(evt) # and this doesn't release the GIL, even while rendering
I noticed there is the same issue with PyQt5 5.15
Could it be possible that in next versions of PySide, QOpenGLWidget.event and eventually QWidget.event would release the GIL ?
Attachments
Issue Links
- relates to
-
PYSIDE-803 QThread Freezes GUI
- Closed
-
PYSIDE-1176 Use allow-thread more often
- Closed
-
PYSIDE-931 Option to control GIL-code-handling in shiboken2
- Closed