# Python performance

Please tell me how to make the Python code below to compute the Fibonacci sequence run faster?

#!/usr/bin/perl
#-------------------------------------------------------------------------------

# Perl vs Python execution time on Fibonacci sequence - run from command line

#-------------------------------------------------------------------------------
use warnings FATAL => qw(all);
use strict;
use Carp;
use Data::Dump qw(dump);
use Data::Table::Text qw(:all);
use feature qw(say current_sub);
use Time::HiRes qw(time);

my \$N = 1e6; # Limit

if (my \$p = time) # Python
{my \$f = owf(undef, <<END);
import math
N = \$N
prev, current = (0,1)
for i in range(N) :
(prev, current) = (current, prev + current)

print(f"Python length: {len(str(current))}, last: {str(current)[-10:]}\n")
END
say STDERR qq(\n\nPython\n\n);
say STDERR qx(python3 \$f);
say STDERR "Python took: ", time-\$p;
}

if (my \$p = time) # Perl
{my \$f = owf(undef, <<‘END’ =~ s(NNNN) (\$N)gsr);
use Math::GMP qw(:constant);

my \$N = NNNN;

my (\$prev, \$current) = (1, 0);

for (0…\$N)
{(\$prev, \$current) = (\$current, \$prev + \$current);
}

print "Perl length: ", length(\$current), ", last: ", substr(\$current, -10), “\n”;
END
say STDERR qq(\n\nPerl\n\n);
say STDERR qx(perl \$f);
say STDERR "Perl took: ", time-\$p;
}

DATA
Python

Python length: 208988, last: 4926937501

Python took: 9.31476497650146

Perl

Perl length: 208988, last: 4926937501

Perl took: 3.88902902603149

Hi Philip,

You seem to have shuffled the Perl and Python code into one big block.

It is difficult to say how you can make the Python code run faster. That
will depend on many factors. The version of Python, and whether it is a
debug build or not, can have a big influence.

If your Python interpreter was built with pydebug, it will probably be a
lot slower than a non-debug build, but I don’t know how much more
slower.

You can check by inspecting sys.flags:

import sys
print(sys.flags)

which I think will tell you if the build has the debugging code added.

Other than that, what version of Python are you running? Did you run the
Perl and Python code on the same machine under the same conditions?

The Python code is being run using Python 3.6.9 :

Python 3.6.9 (default, Jul 17 2020, 12:50:27)
[GCC 8.4.0] on linux

import sys
print(sys.flags)
sys.flags(debug=0, inspect=0, interactive=0, optimize=0, dont_write_bytecode=0, no_user_site=0, no_site=0, ignore_environment=0, verbose=0, bytes_warning=0, quiet=0, hash_randomization=1, isolated=0)

The containing program runs and times each variant on the same machine one after the other in an attempt to make a realistic comparison. Changing the order of the run does not seem to have any effect. The code has all been packaged together into one file to make it easy for any-one else to run the test suite on their machine to see if they get a different outcome.

I appreciate your time spent helping me resolve this interesting problem!

Wait, I’ve just read your code again, and I think I might have
misinterpreted what I saw.

You are not comparing Perl versus Python. You are comparing:

(1) Perl running on its own

versus:

(2) Perl calling Python, then running more Perl code.

Start by pulling the Python code out into a separate file, not buried
inside the Perl code:

# fib.py
N = 10**6
prev, current = (0,1)
for i in range(N) :
(prev, current) = (current, prev + current)

print(f"Python length: {len(str(current))}, last: {str(current)[-10:]}\\n")

Then run this from the bash shell (the \$ or maybe % prompt):

time python3 fib.py

I couldn’t get the Perl script to work on my machine, but you can do a
similar thing: put the Perl-only code in a separate file, then run
something like time perl fib.pl.

Your perl program uses GMP. It is very optimized library.

If the perl program use use bigint; instead, the perl program is much slower than Python.

If you want to use gmp, you can install gmpy2 via pip install gmpy2. (You need to install some dependency libraries).

from gmpy2 import mpz

N = 10**6

def main():
prev, current = mpz(0),mpz(1)
for i in range(N) :
(prev, current) = (current, prev + current)

print(f"Python length: {len(str(current))}, last: {str(current)[-10:]}\n")

main()

Now Python program is as fast as Perl program.