Re: Threads and Progress Monitors
--- 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
--- 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
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
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
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
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
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
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
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
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
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
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