how to start a new thread from a GUI
Brian Kelley
bkelley at wi.mit.edu
Fri Aug 17 12:28:29 EDT 2001
Graham Ashton wrote:
>If you made the client and server talk to each other via something like
>XML-RPC then you could even put your daemon on a different machine if you
>wanted, allowing clients to connect over the network and farm jobs out to
>a server.
>
> http://www.onlamp.com/pub/a/python/2000/11/22/xmlrpcclient.html
>
>With RPC you can execute procedures, or methods, on remote systems. So
>you'd have one RPC method to start the processing job, and one to
>retrieve the status of the job or the final answer.
>
Right, this is just a wire protocol albeit with a simpler interface than
Corba/COM etc. But you still need to hook into the GUI's event loop to
handle events. You can't just block and wait for a response, the GUI
still needs to respond to events.
This has been my experience with every GUI system I've looked at (except
mozilla actually I think they run javascript functions in seperate
threads of execution). The issue is that you have to know how to hook
into the event loop using the GUI toolkits version of signal or alarm or
whatever. Like I mentioned there are plenty of remote proxies out there
to run processes on other machines, the trick is keeping the GUI
responsive during long running processes.
What I would like to see is a lightweigh framework for handling any
proxy that delegates to the toolkit, something like:
class LongRunningTask:
class TkinterTask(LongRunningTask)
class GtkTask(LongRunningTask)
class QTTask(LongRunningTask)
class XMLRPCTask(LongRunningTask)
Each task would preserve a model, controller interface where a model is
a class (or interface, see below) and a controller is a class (or interface)
self.task = GtkTask(controller=self, task=task)
GtkTask starts up task and delegates all calls to the task in it's new
process. All calls from the task to the controller are also delegated
appropriately. Now the task can be started out of process, in process,
through a corba mechanism or what not.
I gave a talk at the O'Reilly Open Source conference about this type of
thing. The gist was to automagically start a task running out of
process and hook up an event model that could send python messages back
and forth to the children through any applicable wire protocol. Mitch
Chapman showed me the joys of actually hiding this from the developer
back at Bioreason. He made a GtkTask class that automagically ran
relatively arbitrary python code in another process. We made a mistake
and explained the process to our developers but would have been much
better off just saying "do this and don't worry about it"
For example the GtkTask starts up a piece of code in another process and
uses pipes to send messages back and forth so when the user executes
something like
wire protocol
Controller <----------------> Task
Event Loop Task event Loop
class Controller:
result = self.task.doSomething()
this gets propgated across the wire protocol and gets executed in the
task's namespace. XMLRPC is a dandy wire protocol for doing this but it
still needs to interact with the GUI's event loop, especially for events
(i.e. when the task has to call a method on the Controller for instance)
The Task event loop is a bit simpler since we can use Python's built in
select, signal or whatever to do the polling.
Obviously this would be limited in scope for simplicity. The relevant
points are
1) Uses a controller/model method (where the model is a task here)
2) Asynchronous I/O between controller and model
3) The class has do be it's own interface, that is no __getattr__ or
__setattr__ tricks or similar. This is for the automagic part.
4) Only marshallable/picklable data can be seent between the two and all
data is immutable. I.e. changing an object on one side doesn't change
it on the other, it must be passed back.
5) Processes must be killable! This is easier with pipes and pids and
the like, it's harder with COM/Corba and threads.
This would handle 99% of the issues I have seen for GUIs diehards can
work with COM/Corba (although they still have to hook into the event loop!)
===========
About interfaces:
I used to think that Python's classes were pretty good descriptions of
interfaces. I still think that they are (within reason). The problem
is that python is to dynamic. For example I wrote a COM policy to wrap
arbitrary python objects and query their interfaces so that any object
could become a COM object. There was one simple rule:
Any method/attribute that begins with "_" was considered private and not
exposed.
It worked well but I had a major problem. Cached or lazily evaluated
attributes. Oops, they can't be seen across the wire.
That said, it worked well enough to start me thinking about the task
issue at hand. I think this is a small price to pay in this
circumstance and have had pretty good luck telling my developers about
how to use the wrapped classes. That being said I sat in on Jim
Fulton's "Future of Zope" birds of a feather and quickly realized that
the added complexity of interfaces reduces time and effort down stream.
I think this is possibly more true with novices ironically enough.
Hopefully I'm making sense. I know Mitch will correct me on invalid
points at least.
Cheers
Brian Kelley
Whitehead Institute for Biomedical Research
More information about the Python-list
mailing list