Сколько памяти занимает программа python

Содержание

Python – это фантастический язык программирования. Он также известен как довольно медленный, в основном из-за его огромной гибкости и динамических характеристик. Для многих приложений и областей это не проблема из-за их требований и различных методов оптимизации. Менее известно, что графы объектов Python (вложенные словари списков, кортежей и примитивных типов) занимают значительный объем памяти. Это может быть гораздо более серьезным ограничивающим фактором из-за его влияния на кеширование, виртуальную память, многопользовательскую работу с другими программами и в целом более быстрое исчерпание доступной памяти, которая является дефицитным и дорогим ресурсом.

Оказывается, нетривиально выяснить, сколько памяти фактически потребляется. В этой статье я расскажу о тонкостях управления памятью объекта Python и покажу, как точно измерить потребляемую память.

В этой статье я остановлюсь исключительно на CPython – основной реализации языка программирования Python. Эксперименты и выводы здесь не относятся к другим реализациям Python, таким как IronPython, Jython и PyPy.

Как узнать сколько памяти занимает объект на python short #shorts

Также я запустил числа на 64-битном Python 2.7. В Python 3 числа иногда немного отличаются (особенно для строк, которые всегда являются Unicode), но концепции одинаковы.

Практическое исследование использования памяти Python

Сначала давайте немного разберемся и получим конкретное представление о фактическом использовании памяти объектами Python.

Встроенная функция sys.getsizeof ()

Модуль sys стандартной библиотеки предоставляет функцию getsizeof () . Эта функция принимает объект (и необязательный параметр по умолчанию), вызывает метод sizeof () объекта и возвращает результат, поэтому вы также можете сделать ваши объекты инспектируемыми.

Измерение памяти объектов Python

Давайте начнем с некоторых числовых типов:

“ `python import sys

sys.getsizeof (5) 24 “ `

Интересный. Целое число занимает 24 байта.

python sys.getsizeof(5.3) 24

Хм … float также занимает 24 байта.

python from decimal import Decimal sys.getsizeof(Decimal(5.3)) 80

Вау. 80 байт! Это действительно заставляет задуматься о том, хотите ли вы представлять большое количество вещественных чисел как числа с плавающей запятой или десятичные дроби.

Давайте перейдем к строкам и коллекциям:

“ `python sys.getsizeof (”) 37 sys.getsizeof (‘1’) 38 sys.getsizeof (‘1234’) 41

sys.getsizeof (u ”) 50 sys.getsizeof (u’1 ‘) 52 sys.getsizeof (u’1234’) 58 “ `

OK. Пустая строка занимает 37 байтов, и каждый дополнительный символ добавляет еще один байт. Это многое говорит о компромиссе между сохранением нескольких коротких строк, когда вы будете платить 37 байтов за каждую, и одной длинной строкой, где вы платите только один раз.

Строки Unicode ведут себя аналогично, за исключением того, что служебные данные составляют 50 байтов, и каждый дополнительный символ добавляет 2 байта. Это нужно учитывать, если вы используете библиотеки, которые возвращают строки Unicode, но ваш текст может быть представлен в виде простых строк.

Управление памятью в python

Кстати, в Python 3 строки всегда имеют Unicode, а служебные данные составляют 49 байт (они где-то сохранили байт). Объект байтов имеет служебную информацию только 33 байта. Если у вас есть программа, которая обрабатывает много коротких строк в памяти, и вы заботитесь о производительности, рассмотрите Python 3.

python sys.getsizeof([]) 72 sys.getsizeof([1]) 88 sys.getsizeof([1, 2, 3, 4]) 104 sys.getsizeof([‘a long longlong string’])

В чем дело? Пустой список занимает 72 байта, но каждое дополнительное int добавляет всего 8 байтов, где размер int составляет 24 байта. Список, который содержит длинную строку, занимает всего 80 байтов.

Ответ прост. Список не содержит сами объекты int. Он просто содержит 8-байтовый (в 64-битных версиях CPython) указатель на фактический объект int. Это означает, что функция getsizeof () не возвращает фактическую память списка и всех объектов, которые он содержит, а только память списка и указатели на его объекты. В следующем разделе я представлю функцию deep_getsizeof (), которая решает эту проблему.

python sys.getsizeof(()) 56 sys.getsizeof((1,)) 64 sys.getsizeof((1, 2, 3, 4)) 88 sys.getsizeof((‘a long longlong string’,)) 64

История похожа на кортежи. Накладные расходы пустого кортежа составляют 56 байтов против 72 списка. Опять же, эта разница в 16 байтов на последовательность – это низко висящий плод, если у вас есть структура данных с большим количеством небольших неизменяемых последовательностей.

“ `python sys.getsizeof (set ()) 232 sys.getsizeof (set ([1)) 232 sys.getsizeof (set ([1, 2, 3, 4])) 232

sys.getsizeof (<>) 280 sys.getsizeof (dict (a = 1)) 280 sys.getsizeof (dict (a = 1, b = 2, c = 3)) 280 “ `

Наборы и словари якобы вообще не растут, когда вы добавляете предметы, но обратите внимание на огромные накладные расходы.

Суть в том, что у объектов Python огромные фиксированные накладные расходы. Если ваша структура данных состоит из большого количества объектов коллекций, таких как строки, списки и словари, которые содержат небольшое количество элементов каждый, вы платите много.

Функция deep_getsizeof ()

Теперь, когда я напугал вас до полусмерти и продемонстрировал, что sys.getsizeof () может только сказать вам, сколько памяти занимает примитивный объект, давайте посмотрим на более адекватное решение. Функция deep_getsizeof () рекурсивно выполняет детализацию и вычисляет фактическое использование памяти графом объектов Python.

“ `python из импорта коллекций Mapping, контейнер из sys import getsizeof

def deep_getsizeof (o, ids): «” »Найти объем памяти объекта Python

Это рекурсивная функция, которая детализирует граф объектов Python как словарь, содержащий вложенные словари со списками списков и кортежи и наборы. Функция sys.getsizeof делает только небольшой размер. Каждый считает объект внутри контейнера как указатель, независимо от его размера на самом деле.

: param o: объект : param id: :возвращение: «»» d = deep_getsizeof если id (o) в идентификаторах: вернуть 0 r = getsizeof (o) ids.add (идентификатор (о)) если isinstance (o, str) или isinstance (0, unicode): возврат г если isinstance (o, Mapping): вернуть r + сумму (d (k, ids) + d (v, ids) для k, v в o.iteritems ()) если isinstance (o, контейнер): вернуть r + sum (d (x, ids) для x в o) возврат г « `

У этой функции есть несколько интересных аспектов. Он учитывает объекты, на которые ссылаются несколько раз, и учитывает их только один раз, отслеживая идентификаторы объектов. Другая интересная особенность реализации заключается в том, что она в полной мере использует абстрактные базовые классы модуля коллекций. Это позволяет функции очень лаконично обрабатывать любую коллекцию, которая реализует базовые классы Mapping или Container, вместо непосредственного обращения к множеству типов коллекций, таких как: строка, Unicode, байты, список, кортеж, dict, frozendict, OrderedDict, set, frozenset и т. Д. ,

Читайте также:
Чем отличается антивирус появившийся в 1985 году от предыдущих антивирусных программ

Давайте посмотрим на это в действии:

python x = ‘1234567’ deep_getsizeof(x, set()) 44

Строка длиной 7 занимает 44 байта (37 служебных данных + 7 байтов для каждого символа).

python deep_getsizeof([], set()) 72

Пустой список занимает 72 байта (только накладные расходы).

python deep_getsizeof([x], set()) 124

Список, содержащий строку x, занимает 124 байта (72 + 8 + 44).

python deep_getsizeof([x, x, x, x, x], set()) 156

Список, содержащий строку x 5 раз, занимает 156 байтов (72 + 5 * 8 + 44).

Последний пример показывает, что deep_getsizeof () подсчитывает ссылки на один и тот же объект (строку x) только один раз, но подсчитывается указатель каждой ссылки.

Лечит или хитрости

Оказывается, что у CPython есть несколько хитростей, поэтому числа, которые вы получаете из deep_getsizeof (), не полностью отражают использование памяти программой Python.

Подсчет ссылок

Python управляет памятью, используя семантику подсчета ссылок. Когда на объект больше не ссылаются, его память освобождается. Но пока есть ссылка, объект не будет освобожден. Такие вещи, как циклические ссылки, могут вас сильно укусить.

Маленькие объекты

CPython управляет небольшими объектами (менее 256 байтов) в специальных пулах на 8-байтовых границах. Есть пулы для 1-8 байтов, 9-16 байтов и вплоть до 249-256 байтов. Когда выделяется объект размером 10, он выделяется из 16-байтового пула для объектов размером 9-16 байт. Таким образом, даже если он содержит только 10 байтов данных, он будет стоить 16 байтов памяти.

Если вы выделяете 1 000 000 объектов размером 10, вы фактически используете 16 000 000 байтов, а не 10 000 000 байтов, как вы можете предположить. Эти 60% накладных расходов явно не тривиальны.

Целые

CPython хранит глобальный список всех целых чисел в диапазоне [-5, 256]. Эта стратегия оптимизации имеет смысл, потому что маленькие целые числа всплывают повсюду, и, учитывая, что каждое целое число занимает 24 байта, оно экономит много памяти для типичной программы.

Это также означает, что CPython предварительно выделяет 266 * 24 = 6384 байта для всех этих целых чисел, даже если вы не используете большинство из них. Вы можете проверить это с помощью функции id (), которая дает указатель на фактический объект. Если вы называете id (x) несколько для любого x в диапазоне [-5, 256], вы будете каждый раз получать один и тот же результат (для одного и того же целого числа). Но если вы попробуете это для целых чисел вне этого диапазона, каждый из них будет отличаться (новый объект создается на лету каждый раз).

Вот несколько примеров из этого диапазона:

“ `python id (-3) 140251817361752

id (-3) 140251817361752

id (-3) 140251817361752

id (201) 140251817366736

id (201) 140251817366736

id (201) 140251817366736 “ `

Вот несколько примеров за пределами диапазона:

“ `python id (301) 140251846945800

id (301) 140251846945776

id (-6) 140251846946960

id (-6) 140251846946936 “ `

Память Python против системной памяти

CPython является своего рода притяжательным. Во многих случаях, когда на объекты памяти в вашей программе больше нет ссылок, они не возвращаются в систему (например, небольшие объекты). Это хорошо для вашей программы, если вы выделяете и освобождаете много объектов (которые принадлежат одному и тому же 8-байтовому пулу), потому что Python не должен беспокоить систему, что относительно дорого. Но это не так хорошо, если ваша программа обычно использует X байтов и при некоторых временных условиях она использует в 100 раз больше (например, анализирует и обрабатывает большой файл конфигурации только при запуске).

Теперь эта память 100X может оказаться бесполезной в вашей программе, которая никогда больше не будет использоваться, и система не сможет выделить ее другим программам. Ирония заключается в том, что если вы используете модуль обработки для запуска нескольких экземпляров вашей программы, вы строго ограничите количество экземпляров, которые вы можете запускать на данном компьютере.

Профилировщик памяти

“ `python из профиля импорта memory_profiler

печать «Готово!» если __name__ == ‘__main__’: main () « `

Как вы можете видеть, 22,9 МБ дополнительной памяти занимают. Причина, по которой память не увеличивается при добавлении целых чисел как внутри, так и вне диапазона [-5, 256], а также при добавлении строки, заключается в том, что во всех случаях используется один объект.

Непонятно, почему первый цикл диапазона (100000) в строке 8 добавляет 4,2 МБ, а второй в строке 10 добавляет всего 0,4 МБ, а третий цикл в строке 12 добавляет 0,8 МБ. Наконец, при удалении списков a, b и c освобождается -0.6MB для a и c, но для b добавляется 0.2MB. Я не могу иметь много смысла из этих результатов.

Вывод

CPython использует много памяти для своих объектов. Он использует различные приемы и оптимизации для управления памятью. Отслеживая использование памяти вашим объектом и зная модель управления памятью, вы можете значительно уменьшить объем памяти вашей программы.

Выучить питон

Изучите Python с нашим полным руководством по питону, независимо от того, начинаете ли вы или начинающий программист, ищущий новые навыки.

Источник: coderlessons.com

Как работает память в Python

Python многое делает за нас. Мы привыкли не заботиться об управлении памятью и о написании соответствующего кода. Пусть эти процессы и скрыты, но без их понимания трудно подготовить производительный код для высоконагруженных задач. Сайт proglib.io опубликовал статью, в которой рассматривается модель памяти Python и то, как интерпретатор Python взаимодействует с оперативной памятью компьютера.

Диспетчер памяти: «командовать парадом буду я»

Python — это интерпретируемый язык программирования, поэтому перед запуском программы код на языке Python компилируется в машиночитаемые инструкции — байт-код. Инструкции байт-кода интерпретируются виртуальной машиной, определяемой реализацией языка, например, стандартной — CPython.

Блок

Блок содержит не более одного объекта Python и находится в одном из трех состояний:

  1. untouched — блок еще не использовался для хранения данных;
  2. free — блок использовался механизмом памяти, но больше не содержит используемых программой данных;
  3. allocated — блок хранит данные, необходимые для выполнения программы.

В пределах пула блоки free организованы в односвязный список с указателем freeblock . Если аллокатору для выделения памяти не хватит блоков списка freeblock , он задействует блоки untouched . Освобождение памяти означает всего лишь то, что аллокатор меняет статус блока с allocated на free и начинает отслеживать блок в списке freeblock .

Пул

Пул может находиться в одном из трех состояний: used (занят), full (заполнен), empty (пуст). Пустые пулы отличаются от занятых отсутствием блоков allocated и тем, что для них пока не определен size class . Пулы full полностью заполнены блоками allocated и недоступны для записи. Стоит освободиться любому из блоков заполненного пула — и он помечается как used .

Пулы одного типа и одного размера блоков организованы в двусвязные списки. Это позволяет алгоритму легко находить доступное пространство для блока заданного размера. Алгоритм проверяет список usedpools и размещает блок в доступном пуле. Если в usedpools нет ни одного подходящего пула для запроса, алгоритм использует пул из списка freepools , который отслеживает пулы в состоянии empty .

Арена

Арены содержат пулы любых видов и организованы в двусвязный список usable_arenas . Список отсортирован по количеству доступных пустых пулов. Чем меньше в арене таких пулов, тем она ближе к началу списка. Для размещения новых данных выбирается область, наиболее заполненная данными.

Читайте также:
Что значит недоступна для почтовых программ pop3

Информацию о текущем распределении памяти в аренах, пулах и блоках можно посмотреть, запустив функцию sys._debugmallocstats() :

>>> import sys >>> sys._debugmallocstats() Small block threshold = 512, in 32 size classes. class size num pools blocks in use avail blocks —— —- ——— ————- ———— 0 16 1 212 41 1 32 6 629 127 2 48 28 2317 35 3 64 118 7386 48 4 80 104 5164 36 5 96 17 696 18 6 112 11 372 24 7 128 7 212 5 8 144 37 1014 22 9 160 7 174 1 10 176 64 1426 46 11 192 4 66 18 12 208 3 42 15 13 224 11 181 17 14 240 5 65 15 15 256 3 35 10 16 272 2 23 5 17 288 3 28 14 18 304 15 184 11 19 320 2 17 7 20 336 2 14 10 21 352 2 13 9 22 368 2 15 7 23 384 1 9 1 24 400 3 23 7 25 416 4 31 5 26 432 6 42 12 27 448 4 28 8 28 464 4 26 6 29 480 4 27 5 30 496 5 33 7 31 512 6 37 5 # arenas allocated total = 10 # arenas reclaimed = 2 # arenas highwater mark = 8 # arenas allocated current = 8 8 arenas * 262144 bytes/arena = 2,097,152

Чтобы не произошло утечки памяти, диспетчер памяти должен отследить, что вся выделенная память освободится после завершения работы программы. То есть при завершении программы CPython дает задание очистить все арены.

Именно количество используемых арен определяет объем оперативной памяти, занимаемой программой на Python — если в арене все пулы в состоянии empty , СPython делает запрос на освобождение этого участка виртуальной памяти. Но уже понятно: чтобы пулы стали empty , все их блоки должны быть free или untouched . Получается, нужно понять, как CPython освобождает память.

Освобождение памяти: счетчик ссылок, сборщик мусора

Для освобождения памяти используются два механизма: счетчик ссылок и сборщик мусора.

Всё в Python является объектами, а прародителем всех типов объектов в реализации CPython является PyObject. От него наследуются все остальные типы. В PyObject определены счетчик ссылок и указатель на фактический тип объекта. Счетчик ссылок увеличивается на единицу, когда мы создаем что-то, что обращается к объекту, например, сохраняем объект в новой переменной. И наоборот, счетчик уменьшается на единицу, когда мы перестаем ссылаться на объект.

Счетчик ссылок любого объекта можно проверить с помощью sys.getrefcount() . Учтите, что передача объекта в getrefcount() увеличивает счетчик ссылок на 1, так как сам вызов метода создает еще одну ссылку. Когда счетчик уменьшается до нуля, происходит вызов аллокатора для освобождения соответствующих блоков памяти.

>>> import sys >>> a = <> >>> b = a >>> sys.getrefcount(a) 3 >>> del b >>> sys.getrefcount(a) 2

Однако счетчик ссылок неспособен отследить ситуации с циклическими ссылками. К примеру, возможна ситуация, когда два объекта ссылаются друг на друга, но оба уже не используются программой. Для борьбы с такими зависимостями используется сборщик мусора ( garbage collector ).

Если счетчик ссылок является свойством объекта, то сборщик мусора — механизм, который запускается на основе эвристик. Задача этих эвристик — снизить частоту и объем очищаемых данных. Основная стратегия заключается в разделении объектов на поколения: чем больше сборок мусора пережил объект, тем он значимее для выполнения работы программы. Сборщик мусора имеет интерфейс в виде модуля gc.

Сохранение и освобождение блоков памяти требует времени и вычислительных ресурсов. Чем меньше блоков задействовано, тем выше скорость работы программы. Позволим себе дать несколько советов, касающихся экономной работы с памятью:

  1. Обращайте внимание на работу с неизменяемыми объектами. К примеру, вместо использования оператора + для соединения строк используйте методы .join() , .format() или f-строки.
  2. Избегайте вложенных циклов. Создание сложных вложенных циклов приводит к генерации чрезмерно большого количества объектов, занимающих значительную часть виртуальной памяти. Большинство задач, решаемых с помощью вложенных циклов, разрешимы методами модуля itertools.
  3. Используйте кэширование. Если вы знаете, что функция или класс используют или генерируют набор однотипных объектов, применяйте кэширование. Часто для этого достаточно добавить всего лишь один декоратор из библиотеки functools.
  4. Профилируйте код. Если программа начинает «тормозить», то профилирование — самый быстрый способ найти корень всех зол.

На ранних этапах работы с кодом Python можно вполне обойтись стандартными средствами Python. Но по мере разрастания кодовой базы и приближения к коммерческому использованию кода производительность становится одним из ключевых факторов. Многие задачи, связанные с производительностью Python, лежат в области понимания устройства инструмента и конкретной реализации языка. Не пожалейте времени на изучение исходного кода CPython, находящегося в свободном доступе в репозитории на GitHub.

Источники

  • https://docs.python.org/3/c-api/index.html
  • https://realpython.com/python-memory-management/

Источник: techrocks.ru

Советы по оптимизации памяти в Python

Управление памятью в Python — задача не из простых, она требует хорошего понимания объектов и структур данных Python. В отличие от C / C ++, пользователи не могут контролировать управление памятью. Его берет на себя сам Python. Однако, имея некоторое представление о том, как работает Python и о модулях поддержки памяти, мы можем каким-то образом пролить свет на то, как контролировать эту проблему.

Сколько памяти выделяется?

Есть несколько способов получить размер объекта в Python. Вы можете использовать sys.getsizeof() , чтобы получить точный размер объекта, objgraph.show_refs() , чтобы визуализировать структуру объекта, или psutil.Process().memory_info().rss , чтобы получить всю память, выделенную в данный момент.

Еще один вариант — tracemalloc. Он включен в стандартную библиотеку Python и обеспечивает трассировку выделения памяти на уровне блоков, статистику общего поведения памяти программы.

Наиболее часто используемый файл — это объект arr, который занимает 2 блока памяти общим размером 2637 МБ. Остальные объекты минимальны.

Другой важный метод — оценить, сколько памяти требуется для запуска процесса. Об этом можно догадаться, отслеживая пиковое использование памяти процессом. Чтобы измерить пиковую память, вы можете использовать приведенный ниже код в конце процесса.

### For Linux (in KiB) and MacOS (in bytes) from resource import getrusage, RUSAGE_SELF print(getrusage(RUSAGE_SELF).ru_maxrss) ### For Windows import psutil print(psutil.Process().memory_info().peak_wset)

Имея пиковое число и объем данных, помещенных в процесс, вы можете каким-то образом оценить объем памяти, который будет потреблен для вашего следующего процесса.

1. Используйте Pytorch DataLoader

Обучение большого набора данных является узким местом для вашей памяти, и вы никогда не сможете обучить полную модель, поскольку весь набор данных никогда не умещается в вашей памяти одновременно, особенно для неструктурированных данных, таких как изображение, текст, голос, . Однако, с Pytorch DataLoader вам удастся настроить различные мини-пакеты для всего набора данных, и каждый из них будет непрерывно загружаться в вашу модель (количество образцов зависит от объема вашей памяти). Вы можете увидеть здесь руководство по использованию Pytorch DataLoader.

Однако, если вы хотите обучить модель машинного обучения на табличных данных без использования глубокого обучения (следовательно, без использования Pytorch) или у вас нет доступа к базе данных и вам нужно работать исключительно с памятью, что будет выбором для оптимизация памяти?

2. Оптимизированный тип данных

Понимание того, как данные хранятся и обрабатываются, а также использование оптимального типа данных для задач, сэкономит вам огромное пространство в памяти и время вычислений. В Numpy существует несколько типов, включая логическое (bool), целое число (int), целое число без знака (uint), float, сложное, datetime64, timedelta64, object_ и т. Д.

Читайте также:
Фристайл либре установить программу

### Check numpy integer >>> import numpy as np >>> ii16 = np.iinfo(np.int16) >>> ii16 iinfo(min=-32768, max=32767, dtype=int16) ### Access min value >>> ii16.min -32768

Я сужаю их до uint, int и float, поскольку они наиболее распространены при обучении моделей, обрабатывающих данные в Python. В зависимости от различных потребностей и целей использование достаточного количества типов данных становится жизненно важным ноу-хау. Чтобы проверить минимальные и максимальные значения типа, вы можете использовать функцию numpy.iinfo() и numpy.finfo() для числа с плавающей запятой.

Ниже приводится сводная информация по каждому типу.

Размер файла CSV удваивается, если тип данных преобразован в numpy.float64, который является типом по умолчанию для numpy.array, по сравнению с numpy.float32. Следовательно, float32 — один из оптимальных для использования (тип данных Pytorch также float32).

Поскольку тип данных по умолчанию numpy.float() — float64, а numpy.int() — int64, не забудьте определить dtype при создании массива numpy, чтобы сэкономить огромное количество места в памяти.

При работе с DataFrame будет еще один обычный тип — «объект». Преобразование из объекта в категорию для функции, имеющей различные повторы, ускорит время вычислений.

Ниже приведен пример функции для оптимизации типа данных pd.DataFrame для скаляров и строк.

Еще один способ легко и эффективно уменьшить pd.DataFrame объем памяти — это импортировать данные с определенными столбцами с использованием usercols параметров в pd.read_csv()

3. Избегайте использования глобальных переменных, вместо этого используйте локальные объекты

Python быстрее извлекает локальную переменную, чем глобальную. Более того, объявление слишком большого количества переменных как глобальных приводит к проблеме нехватки памяти, поскольку они остаются в памяти до завершения выполнения программы, а локальные переменные удаляются, как только функция завершается, и освобождает пространство памяти, которое они занимают. Подробнее читайте в разделе Набор реальных навыков, которым должны овладеть специалисты по данным.

4. Используйте ключевое слово yield

Python yield возвращает объект-генератор, который преобразует данное выражение в функцию-генератор. Чтобы получить значения объекта, его необходимо повторить, чтобы прочитать значения, заданные для yield. Чтобы прочитать значения генератора, вы можете использовать list (), for loop или next ().

>>> def say_hello(): >>> yield «HELLO!» >>> SENTENCE = say_hello() >>> print(next(SENTENCE)) HELLO!

Однако генераторы предназначены для одноразового использования. Если вы обращаетесь к нему во второй раз, он возвращается пустым.

>>> def say_hello(): >>> yield «HELLO!» >>> SENTENCE = say_hello() >>> print(next(SENTENCE)) HELLO! >>> print(«calling the generator again: «, list(SENTENCE)) calling the generator again: []

Поскольку значение не возвращается, если объект-генератор не повторяется, память не используется, когда функция Yield определена, в то время как вызов Return в функции приводит к распределению в памяти.

Следовательно, Yield подходит для больших наборов данных или когда вам не нужно хранить все выходные значения, а только одно значение для каждой итерации основной функции.

>>> import sys >>> my_generator_list = (i*2 for i in range(100000)) >>> print(f»My generator is bytes») My generator is 128 bytes >>> timeit(my_generator_list) 10000000 loops, best of 5: 32 ns per loop >>> my_list = [i*2 for i in range(1000000)] >>> print(f»My list is bytes») My list is 824472 bytes >>> timeit(my_list) 10000000 loops, best of 5: 34.5 ns per loop

Глядя на приведенный выше код, понимание списка в 6441 раз тяжелее, чем генератор, и работает медленнее, чем другой генератор.

5. Встроенные методы оптимизации Python

Используйте встроенные функции Python для повышения производительности кода, список функций.

Используйте __slots__ при определении класса

Атрибуты объектов класса Python хранятся в виде словаря. Таким образом, определение тысяч объектов аналогично размещению тысяч словарей в области памяти. И добавление __slots__ (что снижает потери пространства и ускоряет программу, выделяя место для фиксированного количества атрибутов.)

Что касается использования памяти, учитывая, что в объекте класса больше нет __dict__, объем памяти заметно уменьшается с (64 + 16 + 120) = 200 до 56 байт.

Используйте join () вместо «+» для объединения строки

Поскольку строки неизменяемы, каждый раз, когда вы добавляете элемент к строке с помощью оператора «+», новая строка будет выделяться в пространстве памяти. Чем длиннее строка, тем больше потребляется памяти, тем менее эффективным становится код. Использование join() может повысить скорость ›на 30% по сравнению с оператором« + ».

Есть и другие способы повысить скорость и сэкономить память, подробности см. здесь.

itertools

Или сгладьте список с помощью itertools.chain ()

### Concatenate string using ‘+’ operation def add_string_with_plus(iters): s = «» for i in range(iters): s += «abc» assert len(s) == 3*iters ### Concatenate strings using join() function def add_string_with_join(iters): l = [] for i in range(iters): l.append(«abc») s = «».join(l) assert len(s) == 3*iters ### Compare speed >>> timeit(add_string_with_plus(10000)) 100 loops, best of 5: 3.74 ms per loop >>> timeit(add_string_with_join(10000)) 100 loops, best of 5: 2.3 ms per loop

Ознакомьтесь с документацией itertools, чтобы узнать о других методах. Рекомендую изучить:

  • itertools.accumulate (iterable, func): накапливать через итерацию. func может быть operator.func или функциями Python по умолчанию, такими как max, min…
  • itertools.compress (iterable, selectors): фильтрует итерацию с другим (другой объект можно рассматривать как условие)
  • itertools.filterfalse (предикат, итерируемый): отфильтровать и отбросить значения, удовлетворяющие предикату. Это полезно и быстро для фильтрации объекта списка.
  • itertools.repeat (object [, times]): повторить значение объекта N раз. Однако я предпочитаю использовать умножение списка [‘hi’]*1000 , чтобы повторять «привет» 1000 раз, чем использовать itertools.repeat(‘hi’, 1000) (12,2 мкс на цикл против 162 мкс на цикл соответственно)
  • itertools.zip_longest (* iterables, fillvalue = None): заархивируйте несколько итераций в кортежи и заполните значение None значением, указанным в fillvalue .

6. Накладные расходы на импорт выписки

Оператор import может быть выполнен из любого места. Однако выполнение вне функции будет выполняться намного быстрее, чем внутренняя, даже если пакет объявлен как глобальная переменная (doit2), но, в свою очередь, занимает больше места в памяти, чем другой.

7. Фрагмент данных

Я с уверенностью могу сказать, что в большинстве случаев вы не используете все свои данные сразу, а загрузка их одним большим пакетом может привести к сбою памяти. Следовательно, разделение данных или загрузка небольшими порциями, обработка порции данных и сохранение результата — один из наиболее полезных методов предотвращения ошибок памяти.

pandas позволяет сделать это с помощью параметров chunksize или iterator в pandas.read_csv() и pandas.read_sql() . sklearn также поддерживает обучение небольшими порциями с помощью partial_fit() method для большинства моделей.

На вынос

Обработка ошибки памяти в Python — сложная задача, и основная причина может быть никогда не обнаружена, если вы пойдете другим путем.

  • Во-первых, выясните, какой процесс / переменная является основной причиной, приводящей к проблеме переполнения памяти.
  • Во-вторых, примените соответствующие методы оптимизации памяти для этого объекта, оцените новый объем памяти и проверьте, решает ли новый проблему проблему.
  • Если нет, попробуйте оптимизировать связанные процессы (например, уменьшить потребление памяти всего процесса, чтобы сэкономить больше места для основного объекта).
  • Попробуйте воспользоваться приведенными выше советами, и, если проблема не исчезнет, ​​подумайте о создании процесса с помощью операции фрагмента / пакетной обработки с поддержкой внешней службы базы данных.

Источник: digitrain.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru