How to make Python run as fast (or faster) than Julia
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Mon Feb 26 05:36:49 EST 2018
On Sun, 25 Feb 2018 19:26:12 -0800, Rick Johnson wrote:
> On Friday, February 23, 2018 at 8:48:55 PM UTC-6, Steven D'Aprano wrote:
> [...]
>> Take the Fibonacci double-recursion benchmark. Okay, it tests how well
>> your language does at making millions of function calls. Why?
>
> Because making "millons of function calls" is what software *DOES*!
You're right -- I worded that badly, and ended up saying something I
didn't really mean. Mea culpa.
Of course over the course of the entire program run, most non-trivial
programmers will end up having millions (if not billions) of function
calls *in total*. But they're not all happening *together*.
What I tried to get across is, how often do we use millions of function
calls to get one value? By default, Python will only allow one thousand
function calls in a stack before raising RecursionError.
py> def bad():
... return bad()
...
py> bad()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in bad
[ previous line repeats 998 times ]
RecursionError: maximum recursion depth exceeded
There's nothing unique about recursion that will trigger this error. Any
call stack of more than 1000 function calls will do it. So forget about
code getting a million functions deep. The average is probably more like
a dozen, perhaps a hundred tops.
[...]
>> For most application code, executing the function is far more costly
>> than the overhead of calling it,
>
> What? Your functions are only called _once_ during the lifetime of your
> code execution? Enough with the leg pulling.
Let me explain what I intended to say.
Here is a really poor estimate of the overhead of calling a function on
my computer, measured in iPython.
In [50]: def call():
....: pass
....:
In [51]: %timeit call()
1000000 loops, best of 3: 717 ns per loop
So, on my computer, in iPython, it takes 717ns to call a function that
does nothing. How long does it take to do the tiniest smidgen of useful
work?
In [52]: def do_something():
....: a = 1
....: b = a+1
....: return b
....:
In [53]: %timeit do_something()
1000000 loops, best of 3: 923 ns per loop
Only an extra 200 ns! Wow, function calls are expensive!!!
(Well, yes, I knew that.) However, let's do some *real* work, not a
Mickey Mouse function like do_something().
In [54]: import pyprimes
In [55]: %timeit pyprimes.nth_prime(100000)
1 loops, best of 3: 2.6 s per loop
I happen to know that calling nth_prime ends up making a couple of
hundred function calls. (Because I wrote it.) Let's call it 10,000
function calls, to be on the safe side. So 10,000 x 800 nanoseconds is
0.008 second, let's call it 0.01 second, which is just 0.4% of the total
cost of calculating the number I was after.
(For the record, that's 1299709.)
So just a trivial fraction of the total cost of the function.
Now I know that this is not always the case. But I maintain that for
*most* (but not all) practical, real-world code that actually does
something useful, the overhead of calling the functions is *usually* (but
not always) low compared to the cost of actually doing whatever it is
that the functions do.
--
Steve
More information about the Python-list
mailing list