Re: Threads and Progress Monitors

2003-05-31 Thread Dulcimer

--- Dave Whipp [EMAIL PROTECTED] wrote:
 Dulcimer wrote:
 sub slow_fn {
my $tick = Timer.new(60, { print ... });
return slow_fn_imp @_;
 }
 
 Now if I could just get the compiler to not complain about that
 unused variable...
  
  
  Maybe I'm being dense
  Why not just
   sub slow_fn {
 Timer.new(1, { print . });
 return slow_fn_imp @_;
   }

Geez. I read my response this morning, which I wrote just before going
to bed, and realized that I must've been dead on my feet.

 The problem is that I want the timer to last for the duration of the 
 slow_fn_imp. If I don't assign it to a variable, then it may be GCed
 at any time.

I was making several assumptions which don't hold, apparently, such as
that the underlying Timer would iterate until stopped. Not an ideal
default, lol I thopught the point was to have the function print
dots repeatedly, tho?

 I've just realised, however, that I'm relying on it being destroyed
 on leaving the scope. I'm not sure that the GC guarentees that.
 I might need
 
sub slow_fn {
  my $timer is last { .stop } = Timer.new(60, { print . });
  return slow_fn_imp @_;
}
 
 but that's starting to get cluttered again.

I don't really consider that clutter. It's clear and to the point,
and Does What You Want. How about 

  sub slow_fn {
my $timer is last { .stop } = 
   new Timer secs = 1, reset = 1, code = {print .};
return slow_fn_imp @_;
  }

so that the timer goes off after a second, prints a dot, and resets
itself to go off again after another second? And I still like the idea
of an expanding temporal window between dots:

  sub slow_fn {
my $pause = 1;
my $timer is last { .stop } = new Timer secs = $pause++,
   reset = {$pause++},
code = {print .};
return slow_fn_imp @_;
  }

As a sidenote, although it would actually reduce readability here, I'm
still trying to wrap my brain thoroughly around the new dynamics of $_.
Would this work correctly maybe?

  sub slow_fn {
my $timer is last { .stop } = new Timer secs = $_=1,
   reset = {$_++},
code = {print .};
return slow_fn_imp @_;
  }

Isn't that $_ proprietary to slow_fn such that it *would* work?

__
Do you Yahoo!?
Yahoo! Calendar - Free online calendar with sync to Outlook(TM).
http://calendar.yahoo.com


Re: Threads and Progress Monitors

2003-05-30 Thread Austin Hastings

--- Dave Whipp [EMAIL PROTECTED] wrote:
 OK, we've beaten the producer/consumer thread/coro model to death.
 Here's a
 different use of threads: how simple can we make this in P6:
 
   sub slow_func
   {
   my $percent_done = 0;
   my $tid = thread { slow_func_imp( \$percent_done ) };
   thread { status_monitor($percent_done) and sleep 60 until
 $tid.done };
   return wait $tid;
   }
 
 I think this would work under Austin's A17; but it feels a bit
 clunky. The
 fact that the sleep 60 isn't broken as soon as the function is done
 is
 untidy, though I wouldn't want to start killing thread.
 
 perhaps:
 
   {
   ...
   $tid = thread { slow... }
   status_monitor(\$percent_done) and wait(60 | $tid) until
 $tid.done;
   return $tid.result;
   }
 
 The thing is, that wait 60 probably can't work -- replace C60
 with
 C$period, and the semantics change. There are some obvious hacks
 that
 could work here: but is there a really nice solution. Ideally, we
 won't need
 the low level details such as C$tid

sub slow_func_imp {
  my $pct_done = 0;
  ...
  yield $pct_done++;   # Per my recent message
  ...
}

sub slow_func {
  my $tid := thread slow_func_imp;

  status_monitor($tid.resume)
while $tid.active;
}




Re: Threads and Progress Monitors

2003-05-30 Thread Michael Lazzaro
On Thursday, May 29, 2003, at 10:47 AM, Dave Whipp wrote:

OK, we've beaten the producer/consumer thread/coro model to death. 
Here's a
different use of threads: how simple can we make this in P6:
Hey, good example.  Hmm...

Well, for starters I think it wouldn't be a big deal to associate a 
progress attribute with each thread object.  It should be that 
thread's responsibility to fill it out, if it wants to -- so you 
shouldn't ever have to pass \$percent_done as an argument, it should be 
a basic attribute of every thread instance.  That might encourage 
people to add progress calculations to their threads after-the-fact, 
without changing the basic interface of what they wrote.

I'll also claim that I would still prefer the auto-parallel, 
auto-lazy-blocking behavior on the thread results we've mused about 
previously.  So coming from the semantics end, I'd love to see it 
written like this:

   # Declaring a threaded calculation

   sub slow_func_impl is threaded {
   while (...stuff...) {
   ... do stuff ...
   _.thread.progress += 10.0;   # or however you want to 
guesstimate[*] this
   }
   return $result;
   }

   # If you don't care about getting the actual thread object, just the 
result,
   # call it this way:

   {
   ...
   my $result = slow_func_impl(...);
   ...
   return $result;
   }
   # But if you want to get the thread object, so you can monitor it's 
progress,
   # call it this way:

   {
   ...
   my $tid = thread slow_func_impl(...);
   while $tid.active {
   status_monitor($tid.progress);
   sleep 60;
   }
   return $tid.result;
   }
To my eye, that looks pretty darn slick.

MikeL

[*] Huh.  Imagine my surprise to find out that my spellcheck considers 
guesstimate to be a real word.  And I always thought that was just a 
spasmostical pseudolexomangloid.



Re: Threads and Progress Monitors

2003-05-30 Thread Dave Whipp
Michael Lazzaro [EMAIL PROTECTED] wrote in # But if you want
to get the thread object, so you can monitor it's

 {
 ...
 my $tid = thread slow_func_impl(...);
 while $tid.active {
 status_monitor($tid.progress);
 sleep 60;
 }
 return $tid.result;
 }

 To my eye, that looks pretty darn slick.

You might be a bit frustrated if the slow_func_impl took 61 seconds :-(.
How do we interrupt the Csleep? Possibly in the same way as we'd timeout a
blocking IO operations. But I wonder if this could work:

  my $tid = thread slow_func_impl(...);
  until wait $tid, timeout=60
  {
  status_monitor($tid.progress);
  }
  return $tid.result;

Here I assume that Cwait returns a true value if its waited condition
occurs, but false if it times out.

Hmm, A few days ago I tried indroducing a syntax for thread with a
sensitivity list in place of an explict loop-forever thread. Perhaps I can
reuse that syntax:

  my $tid = thread slow_func_impl(...);
  thread $tid | timeout(60)
  {
  when $tid = { return $tid.result }
  default = { status_monitor $tid.progress }
  }

Perhaps a different keyword would be better: Calways as the looping
counterpart to Cwait -- then extend Cwait to accept a code block.

Dave.




Re: Threads and Progress Monitors

2003-05-30 Thread John Macdonald
On Thu, May 29, 2003 at 10:47:35AM -0700, Dave Whipp wrote:
 OK, we've beaten the producer/consumer thread/coro model to death. Here's a
 different use of threads: how simple can we make this in P6:
 
   sub slow_func
   {
   my $percent_done = 0;
   my $tid = thread { slow_func_imp( \$percent_done ) };
   thread { status_monitor($percent_done) and sleep 60 until
 $tid.done };
   return wait $tid;
   }

At first glance, this doesn't need a thread - a
coroutine is sufficient.  Resume the status update
coroutine whenever there has been some progress.
It doesn't wait and poll a status variable, it just
let the slow function work at its own speed without
interruption until there is a reason to change the
display.

In fact, it probably doesn't need to be a coroutine
either.  A subroutine - display_status( $percent ) -
should't require any code state to maintain, just a
bit if data so all it needs is a closure or an object.

At second glance, there is a reason for a higher
powered solution.  If updating the display to a new
status takes a significant amount of time, especially
I/O time, it would both block the slow function
unnecessarily and would update for every percent
point change.  Using a separate process or thread
allows the function to proceed without blocking, and
allows the next update to jmp ahead to the current
actual level, skipping all of the levels that occurred
while the previous display was happening.  Instead of
sleep, though, I'd use a pipeline and read it with
a non-blocking read until there is no data.  Then,
if the status has changed since the last update, do
a display update and repeat the non-blocking read.
If the status has not changed, do a blocking read to
wait for the next status change.


Re: Threads and Progress Monitors

2003-05-30 Thread Dave Whipp
John Macdonald [EMAIL PROTECTED] wrote  At first glance, this
doesn't need a thread - a
  Instead of
 sleep, though, I'd use a pipeline and read it with
 a non-blocking read until there is no data.  ...

++ For the lateral thinking. Definitely a valid solution to the problem, as
given. So I'll change the problem prevent it: the slow fn is a 3rd-party
blob with no access to source code and no progress indication.

sub slow_fn {
   print starting slow operation: this sometimes takes half an hour!\n;
   my $tid = thread { slow_fn_imp @_ };
   $start = time;
   loop {
   wait $tid | timeout(60);
   return $tid.result if $tid.done;
   print ... $(time-$start) seconds\n;
   }
}

Still a bit too complex for my taste: perhaps we can use Ctimeout to
generate exceptions:

  my lazy::threaded $result := { slow_fn_imp @_ };
  loop {
timeout(60);
return $result;
CATCH Timeout { print ...$(time)\n }
 }

At last, no Ctid! (Reminder: the suggested semantics of the threaded
variable were that a FETCH to it blocks until the result of the thread is
available).


Dave.




Re: Threads and Progress Monitors

2003-05-30 Thread Luke Palmer
Dave wrote:
 Still a bit too complex for my taste: perhaps we can use Ctimeout to
 generate exceptions:
 
   my lazy::threaded $result := { slow_fn_imp @_ };
   loop {
 timeout(60);
 return $result;
 CATCH Timeout { print ...$(time)\n }
  }
 
 At last, no Ctid! (Reminder: the suggested semantics of the threaded
 variable were that a FETCH to it blocks until the result of the thread is
 available).

To nitpick:

my $result is lazy::threaded := { slow_fn_imp @_ };

Because lazy::threaded isn't the Ireturn type, it's the Ivariable
type.

loop {
timeout(60);
return $result;
CATCH {
when Timeout { print ...$(time)\n
}
}

Because CCATCH is like Cgiven $!.

I like that elegant use of threaded variables, by the way.

Now write the Ctimeout function :-P.

Luke


Re: Threads and Progress Monitors

2003-05-30 Thread Michael Lazzaro
On Thursday, May 29, 2003, at 12:45 PM, Dave Whipp wrote:
Michael Lazzaro [EMAIL PROTECTED] wrote in # But if 
you want
to get the thread object, so you can monitor it's
{
...
my $tid = thread slow_func_impl(...);
while $tid.active {
status_monitor($tid.progress);
sleep 60;
}
return $tid.result;
}
To my eye, that looks pretty darn slick.
You might be a bit frustrated if the slow_func_impl took 61 seconds 
:-(.
How do we interrupt the Csleep? Possibly in the same way as we'd 
timeout a
blocking IO operations.
Personally, I'd be happy with just making the Csleep a smaller 
number, like one second, or a fifth of a second, or whatever.  You want 
the status_monitor to be updated no more often than it needs to be, but 
often enough that it's not lagging.

But if you really wanted wake-immediately-upon-end, I'd add that as a 
variant of Csleep.  For example, you might want a variant that 
blocked until a given variable changed, just like in debuggers; that 
would allow:

{
my $tid = thread slow_func_impl(...);
while $tid.active {
status_monitor($tid.progress);
sleep( 60, watch = \($tid.progress) ); # do you even 
need the '\'?
}
return $tid.result;
}

... which would sleep 60 seconds, or until the .progress attribute 
changed, whichever came first.

You could make more builtins for that, but I think I'd like them to 
just be Csleep or Cwait variants.  Obvious possibilities:

sleep 60; # sleep 60 seconds
sleep( block = $tid );   # sleep until given thread is complete
sleep( watch = \$var );  # sleep until given var changes value
sleep( 60, block = $tid, watch = [\$var1, \$var2, \$var3] );  
five tests

$tid.sleep(...);# sleep the given thread, instead of this one

MikeL



Re: Threads and Progress Monitors

2003-05-30 Thread Michael Lazzaro
On Thursday, May 29, 2003, at 04:48 PM, Luke Palmer wrote:
To nitpick:

my $result is lazy::threaded := { slow_fn_imp @_ };
Pursuing this lazy-threaded variables notion, a question.  Given:

 sub slow_func is threaded {# me likey this 
auto-parallelizing syntax!
 ...
 }

Would we want to say that _both_ of these have the lazy-blocking 
behavior?

 my $result := slow_func();
 print $result;
 my $result  = slow_func();
 print $result;
Or would the first one block at Cprint, but the second block 
immediately at the C=?

The obvious answer is that the := binding passes through the 
lazyness, but the = assignment doesn't.  But I wonder if that isn't a 
bit too obscure, to put it mildly.

MikeL



Re: Threads and Progress Monitors

2003-05-30 Thread Dulcimer

 sub slow_fn {
my $tick = Timer.new(60, { print ... });
return slow_fn_imp @_;
 }
 
 Now if I could just get the compiler to not complain about that
 unused variable...

Maybe I'm being dense
Why not just
 sub slow_fn {
   Timer.new(1, { print . });
   return slow_fn_imp @_;
 }

or maybe even

 sub slow_fn {
   my $tick = 1;
   Timer.new({$tick++}, { print . });
   return slow_fn_imp @_;
 }
For a slowly slowing timer
?

Or to my taste,
 sub slow_fn {
   Timer.new(60, { print ... });
   return slow_fn_imp @_;
 }

__
Do you Yahoo!?
Yahoo! Calendar - Free online calendar with sync to Outlook(TM).
http://calendar.yahoo.com


Re: Threads and Progress Monitors

2003-05-30 Thread Dave Whipp
Dulcimer wrote:
sub slow_fn {
  my $tick = Timer.new(60, { print ... });
  return slow_fn_imp @_;
}
Now if I could just get the compiler to not complain about that
unused variable...


Maybe I'm being dense
Why not just
 sub slow_fn {
   Timer.new(1, { print . });
   return slow_fn_imp @_;
 }
The problem is that I want the timer to last for the duration of the 
slow_fn_imp. If I don't assign it to a variable, then it may be GCed at 
any time.

I've just realised, however, that I'm relying on it being destroyed on 
leaving the scope. I'm not sure that the GC guarentees that. I might need

  sub slow_fn {
my $timer is last { .stop } = Timer.new(60, { print . });
return slow_fn_imp @_;
  }
but that's starting to get cluttered again.

Dave.



Re: Threads and Progress Monitors

2003-05-30 Thread Paul Johnson

Dave Whipp said:

 I've just realised, however, that I'm relying on it being destroyed on
 leaving the scope. I'm not sure that the GC guarentees that.

GC doesn't, but I would be surprised if Perl 6 doesn't and in that case
Parrot will be accommodating.

Take a look at the recent p6i archives for the gory details.

-- 
Paul Johnson - [EMAIL PROTECTED]
http://www.pjcj.net