Comments 58
Когда речь заходит про «питон и оптимизацию», первым делом приводят пример _slots_ и вторым пунктом — namedtuple (попробуйте и ещё одну статью
С другой стороны, выкладывали же мануалы по установке модулей для вордпрессе, сайт же читают не только профи, всё правильно.
«Power on IBM/PC for dummies».
Я думаю в коде того кто не знает про slots и dict бутылочным горлышком будет далеко не slots, а более банальные вещи.
Хотя как на потребление памяти влияет slots в реальном коде, решаящем реальную задачу было бы интересно почитать. Только если этот реальный код не подогнан специально под slots, типа огромного количества объектов одного класа.
В итоге, после нескольких дней работы девайса без остановки, память просто выжралась вся, хотя объектов было не так уж много.
после нескольких дней работы девайса без остановки, память просто выжралась вся
Очевидно, что причина не в слотсах. И решать нужно проблему, а не лечить симптомы, когда уже всё сдохло.
Как вариант, использовать массивы numpy, тоже думал об этом, но пока не так критично чтобы это переписывать.
Я думаю YaakovTooth, и не только, хочет сказать что slots может только отсрочить проблему на какое-то время, а потом добавится ктоме timestamp еще несколько полей и проблему все равно прийдется решать более основательно.
Конечно никто тут кроме вас не знает вашу задачу и ее ограничения.
Но так на вскидку: неужели все эти кадры надо в памяти хранить, а не прочитал > обработал > при необходимости записал куда-то > выкинул из памяти > побежал дальше.
Ситуацию «интернета нет месяц» я все же не рассматриваю как нереальную, так что данной оптимизации в принципе было достаточно.
Так это память интерпретатора, не имеет отношения к вашему коду.
Более точные измерения есть чуть выше внутри, где я использовал tracemalloc.take_snapshot, для них скриншот не приведен, просто цифры даны в тексте.
1. Выделения памяти пустым скриптом (фактически это память, необходимая самому интерпретатору, чтобы просто запуститься):
dtrace -n 'syscall::mmap:entry { @ = sum(arg1); }' -c "python empty.py"
35950592 (34MB)
2. Создаем скрипт по мотивам вашей логики, без доп. оверхеда:
test.py
class DataItem(object):
# __slots__ = ['name', 'age', 'address']
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
data = []
def foo():
for p in range(100000):
data.append(DataItem("Alex", 42, "middle of nowhere"))
foo()
2.1. Без слотов:
dtrace -n 'syscall::mmap:entry { @ = sum(arg1); }' -c "python test.py"
53514240 (51MB)
2.2. Со слотами:
dtrace -n 'syscall::mmap:entry { @ = sum(arg1); }' -c "python test.py"
42766336 (40MB)
Если вычесть память самого питоновского движка (34MB), получим соотв. 17 и 6 МБ под сами структуры (почти то же самое, что намерили вы).
Интересно, что зависимость не линейная (это уже паттерны выделения памяти ОС): увеличив повторения цикла в 10 раз (1 млн. повторений), получим
182Мб и 291Мб соответственно, еще в 10 раз (10 млн. повторений) получим 1494Мб и 2835Мб, т.е. заголовок статьи можно поменять на «от 1.5 до 2.5 раз».
На всякий случай, большая часть атрибутов из первой картинки — это атрибуты класса. Добавьте в функцию dump вывод id(attr), вызовите ее второй раз с аргументом DataItem и увидите, что почти все адреса совпадают. Соответственно и функцию подсчета нужно модифицировать, чтобы она эти общие для всех инстансов атрибуты не учитывала.
>>> from pympler import asizeof
>>> asizeof.asized(d1, detail=1).format()
<DataItem object at 0x7fde39dc8ba8> size=480 flat=56
__dict__ size=424 flat=112
__class__ size=0 flat=0
Но, да, как пример обход атрибутов — наверное, для понимания полезнее.
Просто для примера, sys.getsizeof("") вернет 33 — да, целых 33 байта на пустую строку! А sys.getsizeof(1) вернет 24 — 24 байта для целого числа
Это какая ОС/версия питон?
Win 7 x64, Python 2.7.15
sys.getsizeof("") # 21
sys.getsizeof(целое_число) # от 12 и выше
sys.getsizeof(dict()) # 140
Win 7 x64, Python 3.6.6
sys.getsizeof("") # 25
sys.getsizeof(целое_число) # от 14 и выше
sys.getsizeof(dict()) # 136
Да ладно у автора еще нормально, бывает и хуже
import sys
v = sys.version.replace("\n", "| ")
print(f'version: {v}')
print(f'string: {sys.getsizeof("")}')
print(f'number: {sys.getsizeof(11)}')
print(f'dict: {sys.getsizeof({})}')
Out
version: 3.6.5 (default, Apr 1 2018, 05:46:30) | [GCC 7.3.0]
string: 49
number: 28
dict: 240
iOS/Linux developer
Но, почему PowerShell и 10?
3.7. Может это синтаксический сахар. А может и нет
import sys
class DataItem(object):
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
d1 = DataItem("Alex", 42, "-")
print ("sys.getsizeof(d1):", sys.getsizeof(d1))
class DataItem1(object):
__slots__ = ['name', 'age', 'address']
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
d2 = DataItem1("Alex", 42, "-")
print ("sys.getsizeof(d2):", sys.getsizeof(d2))
('sys.getsizeof(d1):', 64)
('sys.getsizeof(d2):', 72)
ЧЯДНТ?
P.S.
python -V Python 2.7.15rc1 Ubuntu 18.04.1 LTS
Although how the memory consumption is affected by the slots in the real code, it would be interesting to read the real problem solver. Only if this real code is not tailored specifically for slots, such as a huge number of objects of the same class. Richestsoft
I also described briefly my real task in the first thread as well (you can use google translate to read it:).
— поздно, инфаркт — валидол — скорая.
Садист!!!
Питон это интерпретатор, и естественно, он работает медленнее. Но его библиотеки написаны как раз на Си, и при их грамотном использовании, код лишь чуть уступает по скорости. Еще к питону можно и свои С-библиотеки подключать, да много чего там есть.
На самом деле, Python обманчиво простой язык, с низким порогом входа, но писать на нем эффективные программы далеко не так просто, и требует понимания не меньшего, чем для С-программистов.
print(10**5000 + 23**1200 — 67**150)
Для питона такие большие ЦЕЛЫЕ числа — не проблема. Поэтому они занимают столько много места.
Интересно сколько времени займёт написать на C аналогичный пример?
Для начала, расскажите, в каких областях техники оперируют такими степенями. В жизни вы НИКОГДА с такими числами не столкнетесь.
При работе с криптовалютами.
В одном биткойне 10⁸ сатоши. Всего же в системе общее количество сатоши, если я ничего не напутал — примерно 2.1·10¹⁵ сатоши.
В одном эфире 10¹⁸ wei, а для учёта суммарного total supply понадобится работать с числами порядка 10²⁶. Но при этом в системе используются 256-битные целые, поэтому надо уметь работать с числами порядка 10⁷⁸.
В той же Universa в создаваемых смарт-контрактах (а значит, и токенах) «дробность валюты» вообще не ограничена, даже конкретным размером целых чисел.
И да, не путайте целые числа с double. Все те варианты, которые вы предложили (double/extended), для финансовых операций не подходят в принципе.
И опять же, вы куда-то пошли не в ту степь. Я вам показал наглядный пример, нарушающий ваше предположение «в жизни вы НИКОГДА с такими числами не столкнетесь» — а вы поддержку, по сути, BigInteger-ов (в терминологии Java) называете недостатком. Что ещё тогда «недостаток»? Удобные высокоуровневые фронтенды над epoll? «Спрятанные библиотеки» работы с HTTP на высоком уровне? Нужно больше таких «недостатков», пожалуй.
но питон написан на си… Т е его писали программисты на си… Сразу возникает вопрос — как они не померли и зачем сделали это? Это были садомазохисты видимо...
А вообще, писать ускоряющие С/С++/Cython библиотеки для Python — это мой хлеб. И первое, что дает прирост в десятки, а иногда и сотни раз — отказ от использования питоновских объектов и питоновского же менеджера памяти. Больше всего мне нравится, когда в конце разработки клиент замеряет скорость работы и у него округляются глаза. Вычисления зависели, скажем, как O(n) и клиент начинал уже придумывать, как ему уменьшить «n», чтобы вложиться во временной интервал. А после ускорения оказывалось, что даже самый большой «n» клиента вписывается с запасом в одну миллисекунду.
Python хорош для прототипирования. Для Computer Vision или Machine Learning хорошо пробовать много разных вещей и Python тут раскрывается во всей красе. Но если надо запилить свой математический алгоритм, то это неподходящий инструмент.
If it worked without compromises — then the Python interpreter would enable whatever it does by default…and it doesn’t. So we may deduce that this is not (on balance) a good idea for the majority of programs. HindiNews
Python: как уменьшить расход памяти вдвое, добавив всего одну строчку кода?