In the following snippet, why is py_sqrt2
almost twice as fast as np_sqrt2
?
from time import time
from numpy import sqrt as npsqrt
from math import sqrt as pysqrt
NP_SQRT2 = npsqrt(2.0)
PY_SQRT2 = pysqrt(2.0)
def np_sqrt2():
return NP_SQRT2
def py_sqrt2():
return PY_SQRT2
def main():
samples = 10000000
it = time()
E = sum(np_sqrt2() for _ in range(samples)) / samples
print("executed {} np_sqrt2's in {:.6f} seconds E={}".format(samples, time() - it, E))
it = time()
E = sum(py_sqrt2() for _ in range(samples)) / samples
print("executed {} py_sqrt2's in {:.6f} seconds E={}".format(samples, time() - it, E))
if __name__ == "__main__":
main()
$ python2.7 snippet.py
executed 10000000 np_sqrt2's in 1.380090 seconds E=1.41421356238
executed 10000000 py_sqrt2's in 0.855742 seconds E=1.41421356238
$ python3.6 snippet.py
executed 10000000 np_sqrt2's in 1.628093 seconds E=1.4142135623841212
executed 10000000 py_sqrt2's in 0.932918 seconds E=1.4142135623841212
Notice that they are constant functions that just load from precomputed globals with the same value, and that the constants only differ in how they were computed at program start.
Moreover the disassembly of these functions show that they do as expected and only access the global constants.
In [73]: dis(py_sqrt2)
2 0 LOAD_GLOBAL 0 (PY_SQRT2)
2 RETURN_VALUE
In [74]: dis(np_sqrt2)
2 0 LOAD_GLOBAL 0 (NP_SQRT2)
2 RETURN_VALUE