In [1]:
import time
def dummy1():
time.sleep(0.01)
def dummy2():
time.sleep(0.02)
In [2]:
%%time
dummy1()
In [3]:
%%time
dummy2()
In [4]:
%%timeit -n 10
dummy1()
In [5]:
%%timeit -n 10
dummy2()
In [6]:
import cProfile
cProfile.run('dummy1()',)
For more advanced tool on profiling check this: http://pycallgraph.slowchop.com/en/master/
In [7]:
import random
random_list = [random.randint(0, 10000) for i in range(1000000)]
In [8]:
%%timeit -n 10
sorted(random_list)
In [9]:
%%timeit -n 10
sum(random_list) / len(random_list)
In [10]:
import numpy as np
random_array = np.array(random_list)
In [11]:
%%timeit -n 10
np.mean(random_array)
In [12]:
oldlist = ["alma"]*10000
In [13]:
%%timeit -n 10
newlist = []
for word in oldlist:
newlist.append(word.upper())
In [14]:
%%timeit -n 10
newlist = map(str.upper, oldlist)
Wait, is this that much faster?
In [15]:
%%timeit -n 10
newlist = list(map(str.upper, oldlist))
In [16]:
%%timeit -n 10
newlist = [w.upper() for w in oldlist]
Check these builtin functions:
mapfilterziprangesumenumerateallany... and these packages:
functoolsitertools
In [17]:
def firstn1(n):
num, nums = 0, []
while num < n:
nums.append(num)
num += 1
return nums
sum_of_first_n = sum(firstn1(1000000))
In [18]:
def firstn2(n):
num = 0
while num < n:
yield num
num += 1
sum_of_first_n = sum(firstn2(1000000))
In [19]:
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
In [20]:
%%time
x = [fib(n) for n in range(20)]
In [21]:
from functools import lru_cache
@lru_cache(maxsize=None)
def fib2(n):
if n < 2:
return n
return fib2(n-1) + fib2(n-2)
In [22]:
%%time
x = [fib2(n) for n in range(30)]
In [23]:
fib2.cache_info()
Out[23]:
In [24]:
%%timeit
newlist = []
for word in oldlist:
newlist.append(str.upper(word))
Both newlist.append and word.upper are function references that are reevaluated each time through the loop.
In [25]:
%%timeit
upper = str.upper
newlist = []
append = newlist.append
for word in oldlist:
append(upper(word))
Python accesses local variables much more efficiently than global variables.
In [26]:
def func():
upper = str.upper
newlist = []
append = newlist.append
for word in oldlist:
append(upper(word))
#return newlist
In [27]:
%%timeit
func()
In [28]:
%%timeit
wdict = {}
for word in oldlist:
if word not in wdict:
wdict[word] = 0
wdict[word] += 1
In [29]:
%%timeit
wdict = {}
for word in oldlist:
try:
wdict[word] += 1
except KeyError:
wdict[word] = 1
But considering the example above, you might want to use again the stdlib.
In [30]:
from collections import defaultdict
In [31]:
%%timeit
wdict = defaultdict(int)
for word in oldlist:
wdict[word] += 1
In [32]:
def doit1():
import os.path # import statement inside function
os.path.split('python.py')
import os.path as p # import statement outside function
def doit2():
p.split('Python')
In [33]:
%%timeit
for _ in range(100000):
doit1()
In [34]:
%%timeit
for _ in range(100000):
doit2()
In [35]:
def concat1(strings):
res = ""
for s in strings:
res+=s
return res
def concat2(strings):
return "".join(strings)
str_list = ["alma"]*10000000
In [36]:
%%timeit
concat1(str_list)
In [37]:
%%timeit
concat2(str_list)
So naive concatenating is very expensive, since each "+" creates a new string. Therefore, instead of "+"-ing things together you can use string formatting.
def sum(int a, int b):
cdef int sum = a+b
return sum
Numba gives you the power to speed up your applications with high performance functions written directly in Python. With a few annotations, array-oriented and math-heavy Python code can be just-in-time compiled to native machine instructions, similar in performance to C, C++ and Fortran, without having to switch languages or Python interpreters.
Numba works by generating optimized machine code using the LLVM compiler infrastructure at import time, runtime, or statically (using the included pycc tool). Numba supports compilation of Python to run on either CPU or GPU hardware, and is designed to integrate with the Python scientific software stack.
In [38]:
from numpy import arange
def sum2d(arr):
M, N = arr.shape
result = 0.0
for i in range(M):
for j in range(N):
result += arr[i,j]
return result
a = arange(9).reshape(3,3)
In [39]:
from numba import jit
# jit decorator tells Numba to compile this function.
# The argument types will be inferred by Numba when function is called.
@jit
def sum2d_numba(arr):
M, N = arr.shape
result = 0.0
for i in range(M):
for j in range(N):
result += arr[i,j]
return result
In [40]:
%%time
sum2d(a)
Out[40]:
In [41]:
%%time
sum2d_numba(a)
Out[41]:
In [ ]: