what is the best practice to separate Pygtk and long running thread code

S

seb

Hi,

I am using pygtk for the first times.

I am wondering what would be the best "pattern" to interface pygtk with
a thread.

The thread is collecting informations (over the network for example) or
is doing some long calculations.

I would like also to separate the gui part to the action part so that I
should be easier to maintain.

************************************************************
What should be the best practice in order to achieve this ?
***********************************************************

What I use now is :



1)
the gui is launching the "action" evrey 1 sec and is checking for
message using a queue every second also.

gui.py

.....etc ...
class window1(SimpleGladeApp):
#@-- class window1 }
#@-- init window1.__init__ {
def __init__(self, path='gui.glade',
root='window1',
domain=app_name, kwargs={}):
path = os.path.join(glade_dir, path)
SimpleGladeApp.__init__(self, path, root, domain, **kwargs)
self.q=Queue.Queue()
self.action=act.action(self.q)
gobject.timeout_add (1000,self.action.go) # this is the action
asked
gobject.timeout_add (1000,self.process) # check if a new message is
available in the queue

def process (self):
dir (self.q)
if self.q.empty() == False :
print "from main ",self.q.get()
return True

...etc ....

2)
The action part is making somehow the interface between the running
thread and the gui :
It puts the new information in the queue for the gui to process it
later.


action.py

import os
import gui
import time
import Queue
import Spethread # thread that always run in the background

class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args,
**kwargs)
return cls._instance


class action(Singleton):
def __init__(self, queue):
self.q=queue
self.thread_seb=Spethread.worker()
self.thread_seb.start()
self.go()

def go(self):
if self.thread_seb:
reponse=self.thread_seb.status()
self.q.put(reponse)
else :
self.q.put("le thread n'existe plus ")
return True

def stop(self):
self.thread_seb.die()


3)
The thread part is "just" a thread that should from time to time
time.Sleep in order for action to query if it has some new messages.

Spethread.py

import threading
import time

class worker(threading.Thread):

def __init__(self):
threading.Thread.__init__(self)
self.value=0
self.go_on=1

def run(self):
print "self.go_on=",self.go_on
while self.go_on == 1:
self.value=int(time.time())
res=2
for i in range(0, 100):
res=res^i
print res
time.Sleep(0.01)
def status(self):
return self.value


def die(self):
print "die request"
self.go_on=0


Thanks in advance for sharing this informations.
Sebastien.

PS :
the entire gui.py

gH#@-- python gui.py {
#@-- header gui.py {
#!/usr/bin/env python
# -*- coding: UTF8 -*-

# Python module gui.py
# Autogenerated from gui.glade
# Generated on Wed Sep 20 22:03:00 2006

# Warning: Do not modify any context comment beginning with # @--
# They are required to keep user's code
# Doing so will make it unable for kefir to help you further manage
your project

#@-- header gui.py }
#@-- app gui {
import os
import gobject
import gtk
import action as act
import Queue

from SimpleGladeApp import SimpleGladeApp, bindtextdomain

app_name = 'gui'
app_version = '0.0.1'

glade_dir = ''
locale_dir = ''

bindtextdomain(app_name, locale_dir)

#@-- app gui }
#@-- window window1 {
#@-- class window1 {
class window1(SimpleGladeApp):
#@-- class window1 }
#@-- init window1.__init__ {
def __init__(self, path='gui.glade',
root='window1',
domain=app_name, kwargs={}):
path = os.path.join(glade_dir, path)
SimpleGladeApp.__init__(self, path, root, domain, **kwargs)
self.q=Queue.Queue()
self.action=act.action(self.q)
gobject.timeout_add (1000,self.action.go)
gobject.timeout_add (1000,self.process)
#@-- init window1.__init__ }
#@-- new window1.new {
def new(self):
print 'A new %s has been created' % self.__class__.__name__
#@-- new window1.new }
#@-- custom window1 {
# Write your own methods here
#@-- custom window1 }
#@-- callback window1.on_button1_clicked {
def on_button1_clicked(self, widget, args=[]):
print 'on_button1_clicked called with self.%s' %
widget.get_name()
self.action.stop()
print "arrete de thread"
#@-- callback window1.on_button1_clicked }
def process (self):
dir (self.q)
if self.q.empty() == False :
print "from main ",self.q.get()
return True

#@-- window window1 }
#@-- main gui.py {
#@-- init main {
def main():
#@-- init main }
#@-- body main {
Window1 = window1()
Window1.run()
#@-- body main }
#@-- main gui.py }
#@-- run gui.py {
if __name__ == '__main__':
main()
#@-- run gui.py }
#@-- python gui.py }



the glade file:


<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM
"http://glade.gnome.org/glade-2.0.dtd">

<glade-interface>

<widget class="GtkWindow" id="window1">
<property name="visible">True</property>
<property name="title" translatable="yes">window1</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>

<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>

<child>
<widget class="GtkEntry" id="entry1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes">this is it</property>
<property name="has_frame">True</property>
<property name="invisible_char">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>

<child>
<widget class="GtkButton" id="button1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">button1</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_button1_clicked"
last_modification_time="Wed, 20 Sep 2006 19:59:06 GMT"/>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</child>
</widget>

</glade-interface>
 
T

Thomas Guettler

seb said:
Hi,

I am using pygtk for the first times.

I am wondering what would be the best "pattern" to interface pygtk with
a thread.

The thread is collecting informations (over the network for example) or
is doing some long calculations.

Hi,

I would use several *processes*. If your scripts runs on Unix/Linux
you can use select() on the filedescriptors of the processes you created
with popen. On Windows you need to poll them, but maybe this is
better than threads, too. With idle_add you can get data from
the subproceses. It gets called if there are no actions in the
event-loop.

HTH,
Thomas
 
S

seb

Hi Thomas,

I am running WinXP so that casting processes and getting their results
is not so convenient.

I have tested idle add and it does the job : the thread is running
whenever there is no activity on the gui.
I still do not understand how it can be so responsive 'cause the thread
I am using at the moment do not have any time.sleep(ing).

I am afraid I have still to use an intermediate class between the
computing thread and the gui to send data between the two of them but
now about all the computing time is devoided to the thread.

Thanks a lot !!!

Seb.

ps : the only mod that I have done to the gui.py in the init is

def __init__(self, path='gui.glade',
root='window1',
domain=app_name, kwargs={}):
path = os.path.join(glade_dir, path)
SimpleGladeApp.__init__(self, path, root, domain, **kwargs)
self.q=Queue.Queue()
self.action=act.action(self.q)
gobject.idle_add(self.action.go)
#gobject.timeout_add (1000,self.action.go)
gobject.timeout_add (1000,self.process)
 
S

sjdevnull

seb said:
Hi,

I am using pygtk for the first times.

I am wondering what would be the best "pattern" to interface pygtk with
a thread.

The thread is collecting informations (over the network for example) or
is doing some long calculations.

It sounds like you don't need to share all your memory--any time you're
trying to "seperate" threads, you probably want to be using processes
instead.
 
S

seb

Hi,

I am running on WinXP so that is not so convenient to communicate
between separate processes.

In the past I have used blocking files but it may be a slow
communication way for some applications. It may also be too much
depending on the disk on which the program is run (network drives with
different rights).

It seems that RPC call would do the job but I would have liked
something simplier (although I did not tried it).

The best thing would be to have a queue feature that would be be shared
between processes but as far as I know It does not exists in python.


Thanks.
Seb


Do you know of some features like a queue that
 
S

sjdevnull

seb said:
Hi,

I am running on WinXP so that is not so convenient to communicate
between separate processes.

Can you elaborate?

Windows offers plenty of IPC possibilities, including interprocess
mutexes and semaphores. See for instance:
http://www.codeproject.com/threads/Win32IPC.asp

In the past I've used multiple processes under Python with
activepython's win32pipe for IPC without problems.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,149
Members
46,695
Latest member
StanleyDri

Latest Threads

Top