Re: Updating a TextView with the results of a long, processor-intensive process



On Wed, Apr 14, 2004 at 03:44:57PM -0400, muppet wrote:

Bob Wilkinson said:
On Tue, Apr 13, 2004 at 11:17:21PM -0400, muppet wrote:

On Tuesday, April 13, 2004, at 05:23 PM, Bob Wilkinson wrote:

I have read the FAQ Q: How do i keep my gui updating while doing a
long file read?
and added code to the process_infile routine.
<snip>
However, it only updated my TextView at the end of the processing.

Some sanity-check questions:
- Are you returning control to the event loop?

Implicitly. once the processing routine is finished control returns.
How would I do this explicitly, once the processing routine is
started?

short answer:  either "Gtk2->main_iteration while Gtk2->events_pending;", or
restructure your code.


I have 

  Glib::Idle->add( sub {while (Gtk2->events_pending()) {Gtk2->main_iteration()}});

at the bottom of my GUI code


long answer:  there are several ways, and the choice depends on how hard it is
to adapt your algorithm to the method:

a) put the processing into a child process, communicating via a pipe; then
watch the pipe for events, and update accordingly in the io watch callback.  
this is what you're trying to set up.  (the worker thread model is similar to
this, except you have more communication options.)


I have put the processing into a separate file which I have invoked
via:

     open ($fh, "process $file $arg2 $arg3 .. $argn |") or die "Can't fork";

and then use Gtk2::Helper->add_watch to watch the file.

b) break the processing up into little chunks and put the chunks into a work
queue.  in an idle handler, process the next chunk.  this is how the gimp
remains responsive while applying filters and updating its display.

This isn't easy - my perl code is a thin layer of XS glue around C.

c) at "Strategic points" in your heavy processing loop, process events from
the main loop.  this is a quick and dirty way to do it, and not really a good
design.  if tossing this sort of thing in fixes the problem, then you know
that you need to restructure your code to work like a) or b).


Not really practical, like b).


the key is to keep the event loop running as much as possible, which is why a)
is often best for really long-running and intensive processing --- the
processing is not worried about keeping things responsive, it just worries
about doing its job.

think of your callbacks as interrupt handlers --- they need to do their work
and get out as quickly as possible.  if you exceed your processor bandwidth,
the system becomes unresponsive.


- Is the child doing buffered writes which would result in a chunk at
the end even though it should print out other stuff in the middle?

Not that I am aware of. The processing routine is an XS wrapper
around a C library. The C library "printf"s percentage progress
completed. If I run it from a terminal it appears unbuffered. Prior
to me starting to show this progress in a TextView pane it was
appearing, apparently unbuffered, in the terminal from which the GUI
interface was started.

it should be possible for you to read the child's standard output, parse the
%age numbers, and update a progress bar.


I intended to do this at the next step - I just thought a reasonable
intermediate stage in my learning process would be to just dump the
output of the processing into a part of the GUI (I used a TextBox,
since this was referred to in the FAQ - I have got a VTE terminal to
work - for some notion of the word "work" - it displays the fact
that it will process 2 file - I do terminal->fork_command, and it
processes the second of the 2 neglecting to do anything to the
first. But I guess thats a different problem :-) Also I'm not sure
why I have to pass a dummy first arg to that method. Questions,
questions - but I've only been playing with Gnome2::VTE for an hour.


You need to implement some form of throttling mechanism that allows at
most $n_active_children at a time; then sequential processing becomes
$n_active_children=1.  There are tons of ways to do it, using
semaphores, file locking, a counting reaper, chaining handlers, etc etc.

I tried setting a global lock variable, and to run the children only
when the lock was unset. Unfortunately they ignored me and ran
anyway.

Remember that the parent and child can communicate only via IPC mechanisms ---
they cannot share a lock variable.


Yes - I understand that - but the fork is done from the parent. I
only wanted to perform the fork if the lock is unset. I was setting
the lock prior to the fork, and clearing it afterwards. However,
since it was just forking everything off as a sub-process I guess
that would have been the problem. Forks not taking long. I'll go
back to supplying lists of fielnames to the processing method, and
attempt your last solution mentioned here (undef $/);


And then the queue handler is some object that knows about process
throttling and synchronization and all that.

OK. But all of the GUI seemed insensitive while processing the files
- they typically take about 20-30 seconds to process each file.

This means you're blocking somewhere, possibly in the filehandle read in your
callback.  Where does the code stop?  Either put in some tracer prints or run
in the perl debugger to find out.  Do you get out of the click handler?  Do
you get into your IO watch handler?  Do you get out of it?


OK - I will introduce myself to the debugger - so much time
programming Perl (many years) and still never used the debugger much
- I have got by with warn and Data::Dumper;

I suspect you're blocking on the read in the IO watch handler.  THis:

               my $line = <$fh>;

is going to try to read until it sees a newline.  I typically do

               local $/ = undef;
               $text = <$fh>;

to avoid blocking there.  The minor disadvantage is that you have to handle a
multiline string, but that's not a big deal.


OK - I'll try doing this is the watch handler. I suspect this may
yield some profit.
 
Thanks again for your suggestions and comments.

muppet <scott at asofyet dot org>
_______________________________________________
gtk-perl-list mailing list
gtk-perl-list gnome org
http://mail.gnome.org/mailman/listinfo/gtk-perl-list

Bob
-- 
Everything is possible.  Pass the word.
                -- Rita Mae Brown, "Six of One"

Attachment: signature.asc
Description: Digital signature



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]