Python Forum
Why recursive function consumes more of processing time than loops?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Why recursive function consumes more of processing time than loops?
#1
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
Reply
#2
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))
M83Linux likes this post
Reply
#3
(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
Reply
#4
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.
M83Linux likes this post
Reply
#5
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.
ibreeden and M83Linux like this post
Reply
#6
(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!
Reply
#7
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
ibreeden and M83Linux like this post
Reply
#8
(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
Reply
#9
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.
Reply
#10
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.
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  return next item each time a function is executed User3000 19 2,176 Aug-06-2023, 02:29 PM
Last Post: deanhystad
  with open context inside of a recursive function billykid999 1 552 May-23-2023, 02:37 AM
Last Post: deanhystad
  time function does not work tester_V 4 2,949 Oct-17-2021, 05:48 PM
Last Post: tester_V
  Real Time Audio Processing with Python Sound-Device not working Slartybartfast 2 3,883 Mar-14-2021, 07:20 PM
Last Post: Slartybartfast
  Combine Two Recursive Functions To Create One Recursive Selection Sort Function Jeremy7 12 7,199 Jan-17-2021, 03:02 AM
Last Post: Jeremy7
  Can you end the Time.sleep function boier96 9 9,222 Jan-16-2021, 10:09 PM
Last Post: Serafim
  Real Time signal processing tagalog 2 2,601 Dec-12-2020, 05:23 AM
Last Post: tagalog
  Execution of Another Recursive Function muzikman 5 2,947 Dec-04-2020, 08:13 PM
Last Post: snippsat
  Don't Understand Recursive Function muzikman 9 3,576 Dec-03-2020, 05:10 PM
Last Post: muzikman
  list call problem in generator function using iteration and recursive calls postta 1 1,863 Oct-24-2020, 09:33 PM
Last Post: bowlofred

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020