Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Выполнить профилирование памяти в скриптах. #1863

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
269 changes: 269 additions & 0 deletions Урок 6. Практическое задание/task_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,272 @@
Попытайтесь дополнительно свой декоратор используя ф-цию memory_usage из memory_profiler
С одновременным замером времени (timeit.default_timer())!
"""

from memory_profiler import profile
import memory_profiler
from numpy import array
from pympler import asizeof
from timeit import timeit
from timeit import default_timer
from collections import OrderedDict


def decor(func): # что-то мне тут не нравится
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

что-то мне тут не нравится - что?....

def wrapper(*args, **kwargs):
memory_start = memory_profiler.memory_usage() # начало замера памяти
time_start = default_timer() # начало замера времени
func(*args, **kwargs) # начало замера функции (к которым декоратор стоит)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

начало замера функции (к которым декоратор стоит)
декоратор к функциям не стоит, а применяется

time_diff = default_timer() - time_start # окончание замера времени
memory_end = memory_profiler.memory_usage() # окончание замера памяти
mem_diff = memory_end[0] - memory_start[0]
return f'Выполнение заняло памяти: {mem_diff} MiB \n' \
f'И времени: {time_diff} \n'

return wrapper

# скрипт 1
# ДЗ-4, задание 3 (из имеющегося числа сформировать обратное число)
# взят свой вариант (по ТЗ), не преподавателя


number_cycles = 1000000
enter_number_1 = 159753
enter_number_2 = 159753 # вторая переменная, для отдельного вычсиления, чтобы функции не зависели друг от друга


@decor
def revers_1(): # вариант без изменений
new_list = []
num_position = 1
for i in str(enter_number_2):
new_list.insert(-num_position, i)
num_position = num_position + 1
# print(asizeof.asizeof(new_list))
return new_list # 400 байт


@decor
def revers_2(): # изменённый вариант
new_list = [i for i in str(enter_number_1)] # сипользование LC вместо цикла (ибо быстрее)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

у нас цель - память. при чем здесь скорость?....

new_list = reversed(new_list) # размер 448 байт
# new_list = array(new_list) # для уменьшения размера списка - тогда порядка 112 байт,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LC никак не влияет на память, т.к. массив так и так создается

# но (!) сильно упадёт скорость работы по времени!
# print(*[i for i in new_list]) # если использвать/распаковать список, то размер - 48 байт
# print(asizeof.asizeof(new_list))
return new_list # 448 байт


# print(f'Заполнение: '
# f'{timeit("revers_1()", globals=globals(), number=number_cycles)}')
# print(f'Заполнение: '
# f'{timeit("revers_2()", globals=globals(), number=number_cycles)}')
print(revers_1())
print(revers_2())

"""при изменении памяти ивремени получаются в основном одинаковые результаты,
однако, при вызове функций через timeit (без декоратора) выяснняется, что вторая функция на 20-30% быстрее.
так же во второй функции имеется недостаток - размер new_list - 448 байт (в первой он 400 байт),
при использовании array для "сжатия" существенно (!) упадёт время работы функции (но размер станет 112 байт).
но, если во втором варианте выводить (print(*new_list) или производить иные действия
(например [i for i in new_list] или цикл) с new_list,
то размер составит 48 байт.
закоментированные строки кода не убирал, чтобы посмотреть/запустить с другими параметрами можно было"""
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Алексей, у нас цель -память. при чем здесь timeit?
преподаватель в ступоре..


# скрипт 2
# ДЗ-3, задание 1. (заполнение списка и словаря программно, выполниние набора операций и со списком, и со словарем)
# порядок следования: сначала пример, затем его улучшенная часть

first_list = []
first_list_1 = []
first_dictionary = {}
first_dictionary_1 = {}
second_list = []
second_list_1 = []
second_dictionary = {}
second_dictionary_1 = {}
number_operations = 1000000


@decor # начальный пример (создание списка)
def append_list(lst, x): # Выполнение заняло памяти: 38.32421875 MiB, И времени: 0.12531329999910668
for i in range(x):
lst.append(i)
# print(asizeof.asizeof(lst))
# print('время заполнения списка - ')
return lst # размер 40448720 байт


@decor # изменённая версия (создание списка)
def append_list_1(lst_1, x): # Выполнение заняло памяти: 0.63671875 MiB, И времени: 0.10525219999544788
lst_1 = lst_1 + ([i for i in range(x)]) # использование генератора помогает ускорить создание массива
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

использование генератора помогает ускорить создание массива
аналогичный вопрос

# print(asizeof.asizeof(lst_1))
# print('время заполнения списка - ')
return lst_1 # размер 40000048 байт


print(append_list(first_list, number_operations)) # начальный пример
print(append_list_1(first_list_1, number_operations)) # изменённая версия

"""append_list_1 использован генератор, вместо append сложение (в большинстве тестов оно работает быстрее)
по итогам размер массива стал меньше (40000048 против 40448720),
использование памяти редко превышает допустимое значение,
выполнение по времени примерно на 10% быстрее"""


@decor # начальный пример (создание словаря)
def append_dictionary(dictionary, x): # Выполнение заняло памяти: 70.65234375 MiB, И времени: 0.14390649998676963
for i in range(x):
dictionary[i] = i
# print('время заполнения словаря - ')
# print(asizeof.asizeof(dictionary))
return dictionary # размер 73943128


@decor # изменённая версия (создание словаря)
def append_dictionary_1(dictionary_1, x): # Выполнение заняло памяти: 62.640625 MiB, И времени: 0.08110670000314713
dictionary_1[(i for i in range(x))] = ({i for i in range(x)})
# print('время заполнения словаря - ')
# print(asizeof.asizeof(dictionary_1))
return dictionary_1 # размер 65555296


print(append_dictionary(first_dictionary, number_operations)) # начальный пример
print(append_dictionary_1(first_dictionary_1, number_operations)) # изменённая версия

"""аналогичная ситуация со словарями в append_dictionary_1 - при применении LC
значительно выросла скорость заполнения (примерно вдвое), памяти требуется примерно на 10-16% меньше,
размер словаря стал 65555296 против 73943128"""


@decor # начальный пример (копирование списка)
def operations_list(lst): # Выполнение заняло памяти: 7.6484375 MiB, И времени: 0.11844799999380484
for i in lst:
second_list.append(i)
# print('время копирования списка - ')
# print(asizeof.asizeof(second_list))
return second_list # размер 40448720 байт


@decor # изменённая версия (копирование списка)
def operations_list_1(lst, s_list): # Выполнение заняло памяти: 0.00390625 MiB, И времени: 0.07205769998836331
s_list = s_list + ([i for i in lst])
# print('время копирования списка - ')
# print(asizeof.asizeof(s_list))
return s_list # размер 40000048 байт


print(operations_list(first_list)) # начальный пример
print(operations_list_1(first_list, second_list_1)) # изменённая версия

"""как и в примерах выше, LC вновь выдаёт высокие результаты скорости - примерно в полтора раза,
и пониженное потребление памяти ()практичеки не выходит за пределы,
размер списка уменьшился 40000048 против 40448720"""


@decor # начальный пример (копирование словаря)
def operations_dictionary(dictionary): # Выполнение заняло памяти: 40.34375 MiB, И времени: 0.2272960999980569
for i in dictionary:
second_dictionary[i] = dictionary[i]
# print('время копирования словаря - ')
# print(asizeof.asizeof(second_dictionary))
return second_dictionary # размер 73943128


@decor # изменённая версия (копирование словаря)
def operations_dictionary_1(dictionary, s_dict): # Выполнение заняло памяти: 31.7265625 MiB,
# И времени: 0.0817148000060115
s_dict[(i for i in dictionary)] = ({i for i in dictionary})
# print('время копирования словаря - ')
# print(asizeof.asizeof(s_dict))
# s_dict = array(s_dict)
return s_dict # размер 107498472


print(operations_dictionary(first_dictionary)) # начальный пример
print(operations_dictionary_1(first_dictionary, second_dictionary_1)) # изменённая версия

"""каки в предыдущих примерах LC показал высокую скорость работы (примерно в три раза),
меньшее потребление памяти (в данном случае примерно на 20%).
единственный минус (может неправильно измерял) размер словаря гораздо больше,
почти в полтора раза 107498472 против 73943128 (модуль array не помощет, проверил)"""

# скрипт 3
# ДЗ-5, задание 4
# Поработайте с обычным словарем и OrderedDict.
# Выполните операции, равные по смыслу, с каждым из объектов и сделайте замеры

dictionary_list = {}
dictionary_list_1 = {}
ordered_dict_list = OrderedDict({})
ordered_dict_list_1 = OrderedDict({})
number_fill = 1000


# неизменённый вариант
@decor
def fill_dictionary(): # заполнение словаря - заняло памяти: 0.11328125 MiB, времени 0.00037719999090768397
dictionary_list = {i: i * i for i in range(number_fill)}
return dictionary_list


@decor
def fill_ordered_dict(): # заполнение OrderedDict - заняло памяти: 0.08984375 MiB, времени: 0.0003403000009711832
ordered_dict_list = {i: i * i for i in range(number_fill)}
return ordered_dict_list


@decor
def search_key_1(): # ищем значение по ключу в словаре - заняло времени: 1.170000177808106e-05
dictionary_list.get(1)
return dictionary_list


@decor
def search_key_2(): # ищем значение по ключу в словаре (OrderedDict) - заняло времени: 1.200000406242907e-05
ordered_dict_list.get(1)
return ordered_dict_list


print(fill_dictionary(), '\n', fill_ordered_dict(), '\n',
search_key_1(), '\n', search_key_2())


# изменённый вариант

@decor
def fill_dictionary_1(): # заполнение словаря Выполнение заняло памяти: 0.109375 MiB
# И времени: 0.00031010000384412706
# 0.1015625 MiB после array
dictionary_list_1 = array({i: i * i for i in range(number_fill)})
return dictionary_list_1 # 100408, осле array 112


@decor
def fill_ordered_dict_1(): # заполнение словаря OrderedDict Выполнение заняло памяти: 0.09765625 MiB
# И времени: 0.0003563000063877553
# 0.078125 MiB после array
ordered_dict_list_1 = array({i: i * i for i in range(number_fill)})
return ordered_dict_list_1 # 100408, после array 112


@decor
def search_key_3(): # ищем значение по ключу в словаре И времени: 8.100003469735384e-06
# 1.0500021744519472e-05 после array
dictionary_list_1.get(1)
return dictionary_list_1


@decor
def search_key_4(): # ищем значение по ключу в словаре (OrderedDict) И времени: 1.179997343569994e-05
ordered_dict_list_1.get(1)
return ordered_dict_list_1


print(fill_dictionary_1(), '\n', fill_ordered_dict_1(), '\n',
search_key_3(), '\n', search_key_4())

"""при использовании модуля array существенно уменьшился размер словаря - стал порядка 112, вместо 100480,
на время работы практически не повлияло (в пределах погрешности после нескольких измерений),
на дальнейшие вычисления (поиск по ключу) практически не влияет, кроме search_key_3,
там вероятно увеличение работы по времени порядка 10-20 процентов (бывает уменьшение,
поэтому, как вариант, это погрешность выполнения кода)"""