good chemistry is complicated, and a little bit messy -LW |
|
PerlMonks |
comment on |
( [id://3333]=superdoc: print w/replies, xml ) | Need Help?? |
So I'm playing around with recursive subroutines and have results that are a bit confusing. Consider a normal recursive function: sub factorial { my $num = shift; return 1 if 1 == $num; return $num * factorial($num = 1); } Ordinarily, we expect this to have quite a bit of overhead. Part of the reason for this is that we have deferred part of the calculation. For example, here's what this looks like if we try to calculate 5! 1: factorial(5) 2: (5 * factorial(4)) 3: (5 * (4 * factorial(3))) 4: (5 * (4 * (3 * factorial(2)))) 5: (5 * (4 * (3 * (2 * factorial(1))))) 6: (5 * (4 * (3 * (2 * 1)))) 7: (5 * (4 * (3 * 2))) 8: (5 * (4 * 6)) 9: (5 * 24) 10: (120) The problem with this is that we must defer part of the calculation until we get to the terminal condition (1 == $num, or step 5) of the recursive function. Then we go back through the call stack and finish the calculations. In theory, we get around this by building our our recursive function in such a way so that we don't need to walk back through the call stack, but instead have the value calculated every step of the way and return directly from the last call, which could allow us to skip steps 6 through 9 above. We can do this by rewriting our factorial function to keep track of the current value of the factorial and using the magical goto &sub notation.
After playing with this, I realized that I could do even better by using a lexically scoped subroutine and skipping the symbol table lookup, though it winds up being more cumbersome to program.
While my benchmarks show that the lexically scoped subroutine with goto is slightly faster than the first version using goto, it's considerably slower than the straight recursive function. pdcawley noted in Pure Perl tail call optimization that using this form of goto is not very fast; I'm curious to know why it's so ridiculously slow. I've tested this on 5.8.0 and 5.9.1 (I mention 5.9.1 to make it clear that the memory leak associated with assignment to @_ and calling goto is not the culprit). Benchmark code and results below. Did I do something stupid? I might add that I know an iterative solution is faster. I'm just trying to figure out why the goto is slow.
Update: I realized that I did one thing different in the tests. If I (uselessly) duplicate the assignment to @_ in &_fact1, it's not much faster, but it's still faster.
Cheers, New address of my CGI Course. In reply to Why is goto &sub slow? by Ovid
|
|