in reply to Re: [OT]: threading recursive subroutines.
in thread [OT]: threading recursive subroutines.
Whilst I think that your discussion of the problems is correct, I think your choice of algorithm and your code for demonstrating the problems is problematic. The latter in part because you are using Perl, which I specifically excluded; in part because you then use Coro which IMO clouds the real issues and adds more of its own.
Firstly, Fibonacci is a poor example because it is simply so easy to achieve better performance through mechanisms other than threading. As the only purpose of threading in this context is improving performance, using them for Fibonacci is never going to work effectively.
Whilst the recursive Fibonacci algorithm doesn't lend itself to tail call elimination, it is easily written iteratively for an huge performance gain. Equally, the recursive algorithm can be sped up immensely by simply memoising it.
But more importantly, the iteration/recursion can easily be done away with entirely using Binet's formula:
All of these modifications make it possible to calculate Fibonacci( 1474 ) (the limit of a doubles ability to store the result), more quickly than it is possible to spawn a thread. At least using the current implementation of iThreads. And possibly Coro also.
I realise that you chose it only as a well-known example on which to base your discussion. But if you are going to explore the threading of recursion in Perl, there are simpler ways than your implementations. This does the job:
#! perl -slw use strict; use futures; sub fibonacci { my $n = shift; return $n if $n < 2; my $r1 = futures->new( \&fib_t1, $n -2 ); my $r2 = futures->new( \&fib_t1, $n -1 ); return $r1 + $r2; } sub fib_t1 { my $n = shift; return $n if $n < 2; my $r1 = futures->new( \&fib_t2, $n -2 ); my $r2 = futures->new( \&fib_t2, $n -1 ); return $r1 + $r2; } sub fib_t2 { my $n = shift; return $n if $n < 2; return fib_t2( $n -2 ) + fib_t2( $n -1 ); } printf "$_ : %d\n", fibonacci( $_ ) for 1 .. $ARGV[ 0 ]; __END__ C:\test>885839-t 20 1 : 1 2 : 1 3 : 2 4 : 3 5 : 5 6 : 8 7 : 13 8 : 21 9 : 34 10 : 55 11 : 89 12 : 144 13 : 233 14 : 377 15 : 610 16 : 987 17 : 1597 18 : 2584 19 : 4181 20 : 6765
Where the futures module is:
package futures; use threads; sub TIESCALAR { my( $class, $thread ) = @_; return bless [ $thread ], $class; } sub STORE { die "Futures cannot be assigned to"; } sub FETCH { my $self = shift; my $r = $self->[0]->join; return $r; } sub new { my( $class, $code, @args ) = @_; my $thread = &async( $code, @args ); tie my $future, 'futures', $thread; return $future; } 1;
Using three subs serves to highlight the level dependency, but these could be merged into one sub with conditional statements provided there was some way to determine the number of existing threads.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^3: [OT]: threading recursive subroutines.
by Corion (Patriarch) on Feb 03, 2011 at 09:43 UTC | |
by BrowserUk (Patriarch) on Feb 03, 2011 at 10:30 UTC | |
by Corion (Patriarch) on Feb 03, 2011 at 11:43 UTC | |
|
Re^3: [OT]: threading recursive subroutines.
by ikegami (Patriarch) on Feb 03, 2011 at 08:53 UTC | |
by BrowserUk (Patriarch) on Feb 03, 2011 at 09:56 UTC | |
by BrowserUk (Patriarch) on Feb 04, 2011 at 00:07 UTC |