Numpy и память с большими массивами - PullRequest
0 голосов
/ 13 сентября 2018

Я должен работать с большими массивами, говорит, например, x = np.arange(0, 750*350*365, dtype=np.int32)

Я знаю, что python хранит переменную в памяти, если он имеет хотя бы одну ссылку на нее.

НоДопустим, мне нужно импортировать большой массив, выполнить некоторые математические операции и сохранить меньший массив, вычисленный из большого.Будет ли большой массив все еще находиться в памяти?

Например:

Class Data:
    value = None

def process(myDataInstance):
    x = np.arange(0, 750*350*365, dtype=np.int32)
    ix = numpy.where(x < 50000)
    myDataInstance.value = x[ix]

d = Data()
process(d)

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

будет x все еще в памяти, даже если мы больше не в функции 'процесса'? Редактировать : я знаю, что x будет недоступен, как если бы я напечатал print x вне функции, будет ошибка, потому что он был определен в области действия функции.Я спрашиваю о памяти и ссылке вместо имени переменной.

Если да, следует ли мне использовать myDataInstance.value = x[ix].copy() для создания другого массива, чтобы ссылка была удалена при выходе из функции?

Еслинет, где это копировать?

спасибо за объяснение

Ответы [ 3 ]

0 голосов
/ 13 сентября 2018

Чтобы удалить объект Python an_object из памяти, вызовите del(an_object) и дождитесь начала сбора мусора. На сбор мусора также можно вмешаться вручную с помощью модуля gc на ваш риск.

Важно уточнить, что del(an_object) или аналогичные методы удаления не удаляют объект из памяти, а только удаляют имя an_object из пространства имен.Вам все еще нужно ждать сборки мусора.

ОБНОВЛЕНИЕ Чтобы ответить на комментарий, приведенный ниже, мы можем проверить, является ли фрагмент массива ссылкой на исходный массив или нет, с помощью следующегоcode:

import numpy as np

x_old = np.arange(0,10,1) # x_old = np.array([0,1,2,3,4,5,6,7,8,9])

x_new_1 = x_old[:5] # We slice the array, without calling  .copy()
# x_new = np.array([0,1,2,3,4])

x_old[2]=100 # We change the third element of the original array, from 2 to 100
print(x_new_1) # The output is [  0   1 100   3   4]. x_new_1 is thus a reference to x_old,
# not a new object

x_old[2]= 2 # Restore original value
x_new_2 = x_old[:5].copy() # This time we call .copy() on the slice, or the whole array for that matter.
x_old[2]=100 # again we change the value

print(x_new_2) # The output is array([0, 1, 2, 3, 4])

Следовательно, вызов .copy () для исходного массива создаст новый объект, что позволит вам удалить старый из пространства имен и дождаться его автоматического удаления из памяти.Если вы не вызываете .copy (), вы все еще работаете со ссылкой на старый объект, и, как следствие, все, что происходит с исходным объектом, связывает ссылку.

Что делать, если вы хотитеудалить из памяти часть массива:

1) Скопировать фрагмент исходного массива, который вы хотите сохранить, в новый массив с новым именем.

2) Вызвать del илилюбая другая инструкция удаления в исходном массиве

3) Дождаться его автоматического удаления из памяти

4) Продолжить работу с новым объектом.

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

UPDATE 2

OP, как упомянуто @Lightalchemist в комментарии ниже, код, который вы предоставили, не создает ссылку на x, а скорее на его копию.Код, который вы указали в качестве примера, не соответствует описанию проблемы, с которой вы столкнулись.

0 голосов
/ 13 сентября 2018

Необычное индексирование, в отличие от нарезки, не возвращает представление, поэтому у вас не останется ссылка на ваш большой массив.См. официальное объяснение представлений и копий в Numpy .

Чтобы прямо ответить на ваш вопрос, часть, в которой вы пишете myDataInstance.value = x[ix], - это место, где выполняется копирование.Вы не должны явно вызывать copy, если только вы не выполняете нарезку.

Чтобы глубже вникнуть, можно проверить, является ли переменная представлением массива numpy.Функция Numpy's shares_memory

import numpy as np
X = np.arange(10)
x = X[np.where(X > 5)]
np.shares_memory(X, x)  # This outputs False

x = X[np.where(X >= 0)]
np.shares_memory(X, x)  # Still false

Вы также можете использовать sys.getrefcount(var) для проверки количества ссылок, указывающих на переменную var за один раз.

import sys
X = np.arange(10)
print(sys.getrefcount(X)) # This prints 2
x = X[np.where(X > 0)]
print(sys.getrefcount(X)) # This still prints 2

Обратите внимание, что причина sys.getrefcount(X) печати 2 заключается в том, что 1 ссылка удерживается переменной X, а другая - функцией sys.getrefcount() и , а не x.

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

0 голосов
/ 13 сентября 2018

Переменные, указанные в области вашего процесса (), будут удалены из памяти, как только вы больше не будете выполнять эту функцию. Вы можете увидеть это в действии, выполнив следующее:

class Data:
    value = None

def process(myDataInstance):
    x = np.arange(0, 750*350*365, dtype=np.int32)
    ix = np.where(x < 50000)
    myDataInstance.value = x[ix]

d = Data()
process(d)
print(ix)

>>> Traceback (most recent call last):
  File "/workspace/PRISE/src/datacube/prod_mngr/data_fusion.py", line 26, in <module>
    print(ix)
NameError: name 'ix' is not defined

Вы получаете NameError, поскольку переменная ix определяется только в области действия метода process.

ПРИМЕЧАНИЕ: Если в методе process() было self.ix = np.where(x < 50000), то после строки process(d) вы сможете получить доступ к переменной ix, используя print(Data.ix), поскольку это выделяет переменная для Data() объекта, на который у вас есть глобальная ссылка.

ИЗМЕНИТЬ для дальнейшего уточнения:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...