Python Forum
Why recursive function consumes more of processing time than loops? - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Why recursive function consumes more of processing time than loops? (/thread-33633.html)



Why recursive function consumes more of processing time than loops? - M83Linux - May-11-2021

Hi All,

Why recursive function consumes more processing time than loops?
And, Is it cumbersome for the processor?

def fibonacci(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fibonacci(n-1) + fibonacci(n-2)

print fibonacci(40)
^^^^ this example takes about 1 min, but with loop only few ms


RE: Why recursive function consumes more of processing time than loops? - bowlofred - May-11-2021

I assume your loop is not written identically.

Recursion means a function call. A function call will take more time and memory than just executing a loop. But the difference isn't huge.

But your program is written in a way where you're redoing your work over and over and over. I'm assuming your loop was not written that way. The slowness is due to the algorithm, not inherently the recursion.

If you add a memoization cache to it, it will complete quickly.
from functools import lru_cache

@lru_cache
def fibonacci(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(40))



RE: Why recursive function consumes more of processing time than loops? - M83Linux - May-12-2021

(May-11-2021, 11:50 PM)bowlofred Wrote: If you add a memoization cache to it, it will complete quickly.

Thank You alot Thumbs Up

(May-11-2021, 11:50 PM)bowlofred Wrote:
from functools import lru_cache

i can't import that coz i'm using v2.7


RE: Why recursive function consumes more of processing time than loops? - bowlofred - May-12-2021

Python 2 is very old and there's lots of things that no longer support it. You should figure out what is preventing you from using python 3 and try to address it.


RE: Why recursive function consumes more of processing time than loops? - deanhystad - May-12-2021

I ran this code
def fib(n):
    fib.count += 1
    if n < 2:
        return 1
    else:
        return fib(n-2) + fib(n-1)

fib.count = 0
print(fib(40))
print(fib.count)
The fib function was called 331,160,281 times

Then I ran this code that uses a dictionary to save and reuse partial results:
def fib(n):
    fib.count += 1
    a = partial_results.get(n, None)
    if a is None:
        a = fib(n-2) + fib(n-1)
        partial_results[n] = a
    return a

partial_results = {0:0, 1:1}
fib.count = 0
print(fib(40))
print(fib.count)
This is similar to what Python does for you using the cache, but expanded out so you can see the mechanism. The result was the same, but the fib function is only called 79 times. If I were to compute multiple Fibonacci numbers many of them could be calculated by a single call to fib.

So raw recursion takes longer because it is doing a ridiculous number of function calls calculating the same results over and over and over.


RE: Why recursive function consumes more of processing time than loops? - M83Linux - May-17-2021

(May-12-2021, 03:06 AM)deanhystad Wrote: The fib function was called 331,160,281 times

Shocked
I'm shocked.
trying to understand from where this huge number come!


RE: Why recursive function consumes more of processing time than loops? - deanhystad - May-17-2021

Starting with a really simple case:
fib[4] = fib[3] + fib[2]
fib[4] = (fib[3] = fib[2] + fib[1]) + (fib[2] = fib[1] + fib[0])
fib[4] = (fib[3] = (fib[2] = fib[1] + fib[0]) + fib[1]) + (fib[2] = fib[1] + fib[0])
That's 9 calls to fib().

This code records the number of times fib[n] is called for each value of n:
calls = {}

def fib(n):
    calls[n] = calls.get(n, 0) + 1
    if n < 2:
        return 1
    else:
        return fib(n-1) + fib(n-2)
fib(5)
for n, count in calls.items():
    print(f'{n:3d} : {count:5d}')
print('Total', sum(calls.values()))
Output:
5 : 1 4 : 1 3 : 2 2 : 3 1 : 5 0 : 3 Total 15
Just doubling starting n from 5 to 10 does this:
Output:
10 : 1 9 : 1 8 : 2 7 : 3 6 : 5 5 : 8 4 : 13 3 : 21 2 : 34 1 : 55 0 : 34 Total 177
And this is the horrible thing that happens when n = 40
Output:
40 : 1 39 : 1 38 : 2 37 : 3 36 : 5 35 : 8 34 : 13 33 : 21 32 : 34 31 : 55 30 : 89 29 : 144 28 : 233 27 : 377 26 : 610 25 : 987 24 : 1597 23 : 2584 22 : 4181 21 : 6765 20 : 10946 19 : 17711 18 : 28657 17 : 46368 16 : 75025 15 : 121393 14 : 196418 13 : 317811 12 : 514229 11 : 832040 10 : 1346269 9 : 2178309 8 : 3524578 7 : 5702887 6 : 9227465 5 : 14930352 4 : 24157817 3 : 39088169 2 : 63245986 1 : 102334155 0 : 63245986 Total 331160281



RE: Why recursive function consumes more of processing time than loops? - M83Linux - May-17-2021

(May-17-2021, 06:29 PM)deanhystad Wrote: Starting with a really simple case:

that makes sense now, i benefited a lot from you
thank you


RE: Why recursive function consumes more of processing time than loops? - csr - May-20-2021

This is why using recursion shouldn't be taken for granted. The use of resources can easily become exponential; and the more resources are used per function call, the worse it'll be.

While recursion can provide a simpler and more readable solution to a problem, you'll be able to achieve similar results if you use the right tools. For instance, this code:

def fib(n):
    fibs = []
    for i in range(n + 1):
        if i < 2:
            fibs.append(i)
        else:
            fibs.append(fibs[i - 2] + fibs[i - 1])
    return fibs[-1] if n >= 0 else 0
Provides the same simple solution by making use of a list to save and use the results as we iterate from 0 to n (included). The memory footprint in this case is minimal (only one function call and a list), as we don't take additional steps to keep track of n-1 and n-2 in order to calculate and use these.


RE: Why recursive function consumes more of processing time than loops? - DeaD_EyE - May-20-2021

Quote:Why recursive function consumes more of processing time than loops?

Calling a function takes time and requires also resources. Iterating over something is faster than calling.
A call of a function is for a human very short, but if you do this one million times, you can recognize the difference.