Здесь рассматриваются методики профилировали в Питоне.
Это скорее памятка самому себе, но если кому-то пригодится, буду рад!)
Так же доступна интерактивная версия Ipython Notebook.
http://pynash.org/2013/03/06/timing-and-profiling.html - По теме
https://ru.wikipedia.org/wiki/Множество_Жюлиа - Рассматриваемый пример
https://ru.wikipedia.org/wiki/Множество_Жюлиа - Рассматриваемый пример
In [2]:
# Перед этим pip install line_profiler, memory_profiler
%load_ext line_profiler
%load_ext memory_profiler
In [6]:
from functools import wraps
def timefn(fn):
@wraps(fn)
def measure_time(*args, **kwargs):
t1 = time.time()
result = fn(*args, **kwargs)
t2 = time.time()
print ("@timefn:" + fn.func_name + " took " + str(t2 - t1) + " seconds")
return result
return measure_time
In [5]:
#@timefn
#@profile
def calculate_z_serial_purepython(maxiter, zs, cs):
"""Calculate output list using Julia update rule"""
output = [0] * len(zs)
for i in xrange(len(zs)):
n=0
z = zs[i]
c = cs[i]
while abs(z) < 2 and n < maxiter:
z=z*z+c
n+=1
output[i] = n
return output
In [15]:
import time
x1, x2, y1, y2 = -1.8, 1.8, -1.8, 1.8
c_real, c_imag = -0.62772, -.42193
def calc_pure_python(desired_width, max_iterations):
"""Create a list of complex coordinates (zs) and complex parameters (cs), build Julia set, and display"""
x_step = (float(x2 - x1) / float(desired_width))
y_step = (float(y1 - y2) / float(desired_width))
x=[]
y=[]
ycoord = y2
while ycoord > y1:
y.append(ycoord)
ycoord += y_step
xcoord = x1
while xcoord < x2:
x.append(xcoord)
xcoord += x_step
##################### SHOW PYTHON HEAP
from guppy import hpy;
hp = hpy()
print "heapy after creating y and x lists of floats"
h = hp.heap()
print h
######################
# Build a list of coordinates and the initial condition for each cell.
# Note that our initial condition is a constant and could easily be removed; # we use it to simulate a real-world scenario with several inputs to
# our function.
zs=[]
cs=[]
for ycoord in y:
for xcoord in x:
zs.append(complex(xcoord, ycoord))
cs.append(complex(c_real, c_imag))
print "Length of x:", len(x)
print "Total elements:", len(zs)
start_time = time.time()
output = calculate_z_serial_purepython(max_iterations, zs, cs)
end_time = time.time()
secs = end_time - start_time
print calculate_z_serial_purepython.func_name + " took", secs, "seconds"
# This sum is expected for a 1000^2 grid with 300 iterations. # It catches minor errors we might introduce when we're
# working on a fixed set of inputs.
#assert sum(output) == 33219980
return output
In [6]:
"""
При построении с учетом отттенков серого, цвет меняющийся высоким контрастом дал бы нам представление о том,
где стоимость функции медленно меняется, а где быстро. На данном рисунке, мы имеем линейный цветовую карту:
черный дорого вычислять(>300), серый бесплатен (сразу 0) и белый дешевле максимума(0<x<300).
"""
from PIL import Image, ImageDraw
width = height = 1000
image = Image.new("RGBA", (width, height), (0,0,0,0))
pixels = image.load()
output = calc_pure_python(desired_width=height, max_iterations=300)
#print output
i = 0
x, y = 0, 0
for val in output:
if i and i%height == 0:
y += 1
x = 0
if val == 300:
color = (0, 0, 0)
elif val == 0:
color = (125, 125, 125)
else:
color = (255, 255, 255)
pixels[x, y] = color
i += 1
x += 1
image.show()
Приступим к профайлингу
Производительность
In [7]:
output = calc_pure_python(desired_width=1000, max_iterations=300)
In [41]:
# in IPython (probably because you’re using %run)
%timeit calc_pure_python(desired_width=1000, max_iterations=300)
In [43]:
# cProfile
# this time includes the overhead of using cProfile
%prun calc_pure_python(desired_width=1000, max_iterations=300)
In [21]:
# line_profiler
%lprun -f calculate_z_serial_purepython calc_pure_python(desired_width=1000, max_iterations=300)
In [1]:
z = 0+0j
%timeit abs(z) < 2
n=1
maxiter = 300
%timeit n < maxiter
# Тут можно порассуждать, о правильности порядка abs(z) < 2 and n < maxiter или n < maxiter and abs(z) < 2
# мы знаем, что только 10% точек доходит до 300-го вычисления и при этом проверка n < maxiter в 2 раза дешевле
Память
Основной закон этого мира - это "Закон сохранения энергии" Это он мешает создать нам вечный двигтаель и он же создает проблему перетягивания каната: память - скорость
Понимание использования памяти вашего кода позволяет вам задать себе два вопроса: • Можем ли мы использовать меньше памяти, переписав эту функцию, чтобы работать более эффективно? • Можем ли мы использовать больше оперативной памяти и сохранить ресурсы процессора за счет кэширования?
In [14]:
from calc_pure_python import calc_pure_python2
# NOTE: %mprun can only be used on functions defined in physical files, and not in the IPython environment.
%mprun -f calc_pure_python calc_pure_python2(desired_width=10, max_iterations=300)
In [15]:
import os
os.path.dirname(os.getcwd())
Out[15]:
In [16]:
z = 0+0j
%memit abs(z) < 2
n=1
maxiter = 300
%memit n < maxiter
CherryPy server
In [8]:
def launch_memory_usage_server(port=8080):
import cherrypy
import dowser
cherrypy.tree.mount(dowser.Root())
cherrypy.config.update({
'environment': 'embedded',
'server.socket_port': port
})
cherrypy.engine.start()
In [13]:
import time
x1, x2, y1, y2 = -1.8, 1.8, -1.8, 1.8
c_real, c_imag = -0.62772, -.42193
def calc_pure_python_cherry(desired_width, max_iterations):
"""Create a list of complex coordinates (zs) and complex parameters (cs), build Julia set, and display"""
x_step = (float(x2 - x1) / float(desired_width))
y_step = (float(y1 - y2) / float(desired_width))
x=[]
y=[]
ycoord = y2
while ycoord > y1:
y.append(ycoord)
ycoord += y_step
xcoord = x1
while xcoord < x2:
x.append(xcoord)
xcoord += x_step
# Build a list of coordinates and the initial condition for each cell.
# Note that our initial condition is a constant and could easily be removed; # we use it to simulate a real-world scenario with several inputs to
# our function.
zs=[]
cs=[]
for ycoord in y:
for xcoord in x:
zs.append(complex(xcoord, ycoord))
cs.append(complex(c_real, c_imag))
# тут стартуем сервер
launch_memory_usage_server()
start_time = time.time()
output = calculate_z_serial_purepython(max_iterations, zs, cs)
end_time = time.time()
secs = end_time - start_time
# делаем так, чтобы сервер не потух
print "now waiting..."
while True:
time.sleep(1)
return output
calc_pure_python_cherry(desired_width=1000, max_iterations=300)
Byte Code
Первый столбец содержит номера строк исполнения.Вторая колонка содержит символы - >>; это направления для точек перехода, в других местах в коде.Третий столбец адрес операции вместе с именем операции.Четвертый столбец содержит параметры для работы.Пятая колонна содержит аннотации, чтобы помочь выстроить байт-код с оригинальными параметрами Python.
In [16]:
import dis
dis.dis(calc_pure_python)
Простое правило гласит, что несколько строк байт-кода будет выполняться более медленно, чем меньшим количеством эквивалентных линий байт-кода, использующих встроенные функции.
Я порекомендую всем, кто ищет кредит для бизнеса, г-ну Бенджамину, который помог мне с кредитом в четыре миллиона долларов, чтобы начать свой бизнес, и это было быстро. Когда я получил от них кредит, было удивительно, насколько легко им было работать. Процесс был быстрым и ненадежно. Это был определенно положительный опыт. Избегайте мошенников и свяжитесь с г-ном Бенджамином. lfdsloans@outlook.com. WhatsApp ... + 19893943740. Если вы ищете бизнес-кредит.
ОтветитьУдалить