I just dealt with this problem. I have an application that uses lots of
"C" extensions that don't give the Python interpreter a chance to
"time-slice" different threads. If I had simply had run the CPU
intensive calculations in another thread, the user-interface thread
would not get enough CPU to be responsive.
The GUI thread sends requests to a 'dispatch' thread (using the 'Queue'
mechanism). The 'dispatch' thread in turn sends requests to a "server"
task using 'Pyro' (http://www.xs4all.nl/~irmen/python.html) Pyro lets
you call methods in a remote Python task just as if the class was part
of your task. It functions as a Python<->Python remote procedure call
mechanism.
Even though the computations are being done in a separate task, it is
important to be able to see status messages from the server task.
I captured the output of the remote task by spawning it using
Process2.py, and then used 'input_add' to read the "server's" output.
e.g.:
from Process2 import Process
proc = Process('dq_server', ('->', 1) )
proc.bg()
self.__inputf = input_add( os.fdopen(proc.fd[1],'r'),
GDK.INPUT_READ,
self.__readServerOutput)
def __readServerOutput(self, fp, condition):
line = fp.readline()
threads_enter() # subtle - to avoid deadlock,
#threads_enter() can't proceed readline()
# cleanup on EOF - avoid infinite stream of callbacks
if line == "":
input_remove(self.__inputf)
fp.close()
print 'Server closed\n'
else:
print ' -> %s' % line[0:-1]
threads_leave()
I also redirected standard output to appear in a widget, using code
adapted from
pygtk/examples/ide/gtkcons.py
This allowed me to view both the server's output and the GUI's task
output in a scrolling log window. I've attached my 'MessageWidget' that
implements the scrolling log widget with output redirection.
--
Joe VanAndel
National Center for Atmospheric Research
http://www.atd.ucar.edu/~vanandel/
Internet: [EMAIL PROTECTED]
"""
MessageWidget:
display a scrolled window of messages in a pygtk GtkText widget in a
scrolled frame
"""
import sys
from gnome.ui import *
from gtk import *
from gnome.config import *
import libglade
__id__ = "$Id: $"
__version__ = "$Revision: $"
# from pygtk/examples/ide/gtkcons.py
class gtkoutfile:
'''A fake output file object. It sends output to a gtk text widget,
and if asked for a file number, returns one set on instance creation'''
def __init__(self, w, fn, font):
self.__fn = fn
self.__w = w
self.__font = font
def close(self): pass
flush = close
def fileno(self): return self.__fn
def isatty(self): return 0
def read(self, a): return ''
def readline(self): return ''
def readlines(self): return []
def write(self, s):
#stdout.write(str(self.__w.get_point()) + '\n')
self.__w.freeze()
self.__w.insert(self.__font, self.__w.fg,
self.__w.bg, s)
# force a scroll to bottom
vadj = self.__w.get_vadjustment()
## sys.stderr.write('lower: %d upper: %d value %d\n' % \
## (vadj.lower, vadj.upper,vadj.value))
vadj.set_value(vadj.upper)
self.__w.thaw()
self.__w.queue_draw()
def writelines(self, l):
self.__w.freeze()
for s in l: self.__w.insert(self.__font,
self.__w.fg, self.__w.bg, s)
vadj = self.__w.get_vadjustment()
vadj.set_value(vadj.upper)
self.__w.thaw()
self.__w.queue_draw()
def seek(self, a): raise IOError, (29, 'Illegal seek')
def tell(self): raise IOError, (29, 'Illegal seek')
truncate = tell
class MessageWidget:
def __init__(self, text_w, wordWrap =TRUE):
self.debug = FALSE
print 'MessageWidget:__init__'
self.text = text_w
self.text.style = self.text.get_style()
self.text.fg = self.text.style.fg[STATE_NORMAL]
self.text.bg = self.text.style.white
#self.text.bg = self.text.style.bg[STATE_NORMAL]
self.text.set_word_wrap(wordWrap)
self.text.set_usize(500, 400)
self.normal = load_font(
"-*-helvetica-medium-r-normal-*-*-100-*-*-*-*-*-*")
self.error = load_font(
"-*-helvetica-medium-o-normal-*-12-100-*-*-*-*-*-*")
# set up hooks for standard output.
self.stdout = gtkoutfile(self.text, sys.stdout.fileno(),
self.normal)
self.stderr = gtkoutfile(self.text, sys.stderr.fileno(),
self.error)
def init(self, debug=0):
self.debug = debug
self.text.realize()
# print 'MessageWidget:text realized '
if not self.debug:
sys.stdout, self.stdout = self.stdout, sys.stdout
#sys.stderr, self.stderr = self.stderr, sys.stderr
else:
print 'debug mode : not grabbing standard output'
def restore(self):
if not self.debug:
sys.stdout, self.stdout = self.stdout, sys.stdout
# sys.stderr, self.stderr = self.stderr, sys.stderr
return