I've noticed a few issues using PyQt and pumpThread. It seems that
randomly when users closes Maya it will do 1 of these:
1) Close successfully.
2) Not closes. Instead require 2 close requests by the user.
3) Closes but leaves 1 Maya thread running ( the pumpThread ) and
still consuming Maya's memory footprint
In an attempt to understand the problem I've reconfigured pumpThread
based on Jon's and another user's version posted here (can't remember
who and cant be bothered to hunt for it again, sorry to who ever you
are). I'll blat out my thoughts and you guys can hopefully correct me
or confirm my understanding.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
I've not done any multi threading stuff before, but this is what I
understand is happening with pumpThread and the way in which it's
operating.
pumpThread is spawning 1 sub thread from Maya's main thread. The UI
is executing in that new thread.
threading.Thread( target = pumpQt, args = () )
Whenever a maya cmd is called in the PyQt UI code it is called with
utils.executeDeferred( processor ) in pumpQt block.
This intern is executed in maya's main thread when it can. I simply
added the following line to the pumpQt whille loop print "pump..."
makes sure a maya cmd is called every pumpThread cycle.
As this loop is executing quicker than maya's main loop and stack of
evalDeffered print statements build up in the main thread. In my
pumpThread module I've created a global for the while loop (gPump).
Using killPumpThread I can instantly stop and close the thread. But
Maya is still printing "pump..." untill the stack of evalDeffered cmds
have finished.
Here's my test code with my new pumpThread module
import pumpThread
pumpThread.initializePumpThread()
# Wait 20 secs
pumpThread.killPumpThread()
# only a small number of prints executed after thread is closed. Maybe
2-5 cycle depending
# Load my PyQt UI and leave open and pumping for 20secs
pumpThread.killPumpThread()
# window closes quickly and tread die's in Task Manager. But 926
lines of pump... printed before maya is finished
So how does that relate to the 3 errors above?
1) Close successfully.
Thread has closed in time and Maya has no evaldeffers in the stack
2) Not closes. Instead require 2 close requests by the user.
Thread has closed in time but maya is still pumping
3) Closes but leaves 1 Maya thread running ( the pumpThread ) and
still consuming Maya's memory footprint
Thread didn't close, UI could have been left open or maya not closing
sun threads properly?
It seems I can't do anything about error 2 as this is down to how
much and often the threads are communicating. But I can help on error
3 by calling pumpThread.killPumpThread() with a script job on Maya
exit.
"RANT ON"
I've spent nearly 6 months researching PyQt in Maya and so far
(especially if you are having to support 64bit) I have to say it's
allot of pain to maintain. Maya doesn't play nicely and will crash
with no warning if you try to do something wrong or something it's not
happy with. When you have 12 UI modules and 500 - 3000 lines of code
in each it is a real headache to comment out blocks of code to find
the line that is crashing Maya. Sometimes it's not you. I had one
example where by I was creating a QIcon as a module global, it was
being used allot in the UI. This line had been in for months, but all
of a sudden was crashing Maya. I had to put the QIcon inside a class
to solve the Maya crash. Developing a complex UI as I have with PyQT
with lots of dependencies on Maya tools, like Pymel and clr means that
you loose the ability to run the UI in Wings with debugging.
Something you really need. Instead. I think using C++ Qt would give
you the hooks to run in debug mode with Maya. You wouldn't have to
compile 64bit PyQt as well. But then you loose the benefits of
developing in a scripting environment.
"RANT OFF"
I'm sure that other studios trying to implement PyQT into there
pipeline have faced these issues. I was wondering if anyone else
could shed some light of the pit falls and hoops you are jumping
through.
Anyway here is my edited pumpThread module
-Dave
----------------------------------------------------------------------------------------------------------------------------------------------------------
from PyQt4 import QtCore, QtGui
import maya.utils as utils
import sys
import time
import threading
import gc
import maya.cmds as cmds
pumpedThread = None
app = None
gPump = True
def get_app():
global app
return app
def set_app(i_app):
global app
testAppInstance = QtCore.QCoreApplication.instance()
if testAppInstance:
app = testAppInstance
else:
app = i_app
def get_pt():
global pumpedThread
return pumpedThread
def set_pt(i_pt):
global pumpedThread
pumpedThread = i_pt
def pumpQt():
global app
global gPump
def processor():
app.processEvents()
while gPump:
time.sleep(0.01)
utils.executeDeferred( processor )
#print "pump..."
def killProcess():
global gPump
gPump = False
def killPumpThread():
if get_app():
get_app().closeAllWindows()
if get_pt():
killProcess()
set_pt(None)
set_app(None)
gc.collect()
class QThreader(QtCore.QThread):
'''An attempt to use QThread instead of Threading. Counld get
this to pump in the same fasion'''
def __init__(self, funcPointer, executeDeferred=True):
super(QThreader, self).__init__()
self.runThread = True
self.funcPointer = funcPointer
self.executeDeferred = executeDeferred
def run(self):
time = long(1)
while self.runThread:
self.usleep(time)
if self.executeDeferred:
utils.executeDeferred(self.funcPointer())
else:
self.funcPointer()
def killThread(self):
self.runThread=False
def startThread(self):
self.runThread=True
def initializePumpThread():
global gPump
gPump = True
if get_pt() == None:
set_app(QtGui.QApplication(sys.argv))
set_pt(threading.Thread( target = pumpQt, args = () ))
get_pt().start()
--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/python_inside_maya
-~----------~----~----~----~------~----~------~--~---