This implementation is not paralyzable "for real", besides being a "catastrophe". Yes, you want to know how to calculate different fibonaccis in parallel threads or processes - the answer to that would be an example of threadpool or processpoll (tip, look Concurrent.Futures) - but I won’t touch on that here.
What is not parallelizable is that you cannot have Fibo(10) in the same thread without having calculated Fibo(5) before - even if your Fibo function has Fibo(n-1) and Fibo(n-2) in separate threads/processes, you will have to wait for both of them to end. (and the catastrophe would be even greater - because threads and processes are MUCH heavier in terms of memory consumption than simple calls)
The implementation works very well for didactic purposes, up to Fibonacci of 10 - maybe up to 15 - but if you ask for a Fibonacci of 40 on it, it will crash your computer. 80 will stop possibly the world’s largest supercomputer.
This is because you have two function calls within each Fibonacci call.
Python, to call a function creates in memory a new object of type "frame" - (along with an object for each local variable of the function, etc.. - in this case it will be only the variable 'n' - but being a Python integer uses a good 30 bytes - but the frame has about 400 bytes).
Well, if you ask Fibonacci for "3", that’s the starting frame, plus the Fibo(1) frame, plus the Fibo(2) frame - what your turn calls again Fibo(1) and Fibo(0) -- are 5 calls - now realize that if you ask Fibo(5) these 5 calls to Fibo(3), and 7 more calls to Fibo(4) ? That is: the number of function calls that Voce makes grows with the SQUARE of the number "n" (what we call complexity O(n²) ) - for example, if Fibo(5) uses ai a 1000 bytes (2**10), Fibo(10) will already use 2*20 bytes: 1 megabyte and Fibo (30) a GB.
The solutions are: Use a cache decorator: functools.lru_cache
in your Fibonacci - this will make that for any known value, the function returns immediately, without executing its body (and port without two other calls) - that is, to calculate Fibo(7), Fibo(6) will be called once, but when Fibo(5) is called, its value will already be known, and there will be no need for new calls to the values 4, 3, 2, 1, 0 in the branch of (5).
But better still: leave the recursive example to understand recursion on the whiteboard, and write the function interactively - pass away from the exponential form.
Only one observation that can be useful to you, even if you do a parallel run of CPU operations bound with Threads, python will run internally in only one thread thanks to GIL (global Internal lock). So for bound CPU operations, use multiprocess
– drgarcia1986
If you want performance use a recursive function with the two previous numbers as parameter, so it only needs to be called once and will not double each call. The code would look like this: def f(i,j,n): Return f(j,i+j,n-1) if n Else i; Hence the Fibonacci function would look like this: def Fibonacci(n): Return f(1,1,n-1); See executing on ideone here: https://ideone.com/7rXz0s
– Sérgio Mucciaccia
@drgarcia1986 Python no, the Cpython . GIL is not a feature of language, but of implementation.
– Pablo Almeida
@Pabloalmeida you are absolutely right
– drgarcia1986