Подтвердить что ты не робот

Распределение памяти профилей в Python (с поддержкой массивов Numpy)

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

Я ищу хороший профилировщик, который позволит мне проверить объем памяти, потребляемый различными объектами (я представляю себе копию экземпляра памяти для cProfile), чтобы я знал, где оптимизировать.

Я слышал приличные вещи о Heapy, но Heapy, к сожалению, не поддерживает массивы Numpy, и большая часть моей программы включает массивы Numpy.

4b9b3361

Ответ 1

Один из способов решения проблемы, если вы вызываете множество разных функций, и вы не знаете, откуда происходит обмен, - использовать новую функцию построения графика из memory_profiler. Сначала вы должны украсить различные функции, которые вы используете с @profile. Для простоты я буду использовать пример examples/numpy_example.py, поставляемый с memory_profiler, который содержит две функции: create_data() и process_data()

Чтобы запустить script, вместо того, чтобы запускать его с помощью интерпретатора Python, вы используете исполняемый файл mprof, то есть

$ mprof run examples/numpy_example.py

Это создаст файл с именем mprofile_??????????.dat, где? будут содержать цифры, представляющие текущую дату. Чтобы построить результат, просто введите mprof plot и он сгенерирует график, подобный этому (если у вас есть несколько файлов .dat, он всегда будет последним):

output of memory_profiler's mprof

Здесь вы видите потребление памяти, с помощью скобок, указывающих, когда вы вводите/оставляете текущую функцию. Таким образом, легко видеть, что функция process_data() имеет пик  потребления памяти. Чтобы продолжить работу в вашей функции, вы можете использовать профилировщик по очереди, чтобы видеть потребление памяти каждой строкой в ​​вашей функции. Это выполняется с помощью

python -m memory_profiler examples/nump_example.py

Это даст вам результат, похожий на этот:

Line #    Mem usage    Increment   Line Contents
================================================
    13                             @profile
    14  223.414 MiB    0.000 MiB   def process_data(data):
    15  414.531 MiB  191.117 MiB       data = np.concatenate(data)
    16  614.621 MiB  200.090 MiB       detrended = scipy.signal.detrend(data, axis=0)
    17  614.621 MiB    0.000 MiB       return detrended

где ясно, что scipy.signal.detrend выделяет огромный объем памяти.

Ответ 2

Посмотрите профайлер памяти. Он обеспечивает профилирование по линиям и интеграцию Ipython, что упрощает ее использование:

In [1]: import numpy as np

In [2]: %memit np.zeros(1e7)
maximum of 3: 70.847656 MB per loop

Обновление

Как уже упоминалось @WickedGrey, при вызове функции более одного раза появляется ошибка (см. github issue tracker), которую я могу воспроизвести:

In [2]: for i in range(10):
   ...:     %memit np.zeros(1e7)
   ...:     
maximum of 1: 70.894531 MB per loop
maximum of 1: 70.894531 MB per loop
maximum of 1: 70.894531 MB per loop
maximum of 1: 70.894531 MB per loop
maximum of 1: 70.894531 MB per loop
maximum of 1: 70.894531 MB per loop
maximum of 1: 70.902344 MB per loop
maximum of 1: 70.902344 MB per loop
maximum of 1: 70.902344 MB per loop
maximum of 1: 70.902344 MB per loop

Однако я не знаю, на какие последствия могут повлиять результаты (кажется, это не так много в моем примере, поэтому в зависимости от вашего варианта использования это может быть полезно), и когда эта проблема может быть исправлена. Я спросил его в github.

Ответ 4

Можете ли вы просто сохранить или разжечь некоторые массивы на диск в файлах tmp, когда их не используете? Это то, что мне пришлось делать в прошлом с большими массивами. Конечно, это замедлит работу программы, но, по крайней мере, она закончится. Если вам не нужны все сразу?

Ответ 5

Вы пробовали valgrind с помощью инструмента massif?

valgrind --tool=massif python yourscript.py

он создаст файл с именем massif.out.xxx, который вы можете проверить с помощью

ms_print massif.out.xxx | less

у него есть всякая полезная информация, но сюжет в самом начале должен быть тем, что вы ищете. Также ознакомьтесь с учебником массива на главной странице valgrind.

Использование valgrind довольно продвинутое, и могут быть более простые способы делать то, что вы ищете.