Есть ли эффективность памяти, получаемая при переносе кода в функции? - PullRequest
3 голосов
/ 28 мая 2009

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

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

например:

def someFunction(aList):
    do things to aList
    that create a dictionary
    return aDict

в конце освобождает больше памяти, чем

>>do things to alist
>>that create a dictionary
>>del(aList)

Это ожидаемое поведение?

ИЗМЕНИТЬ добавленный пример кода

Когда эта функция завершает работу, PF Usage показывает увеличение примерно на 100 МБ, в filingsList около 8 миллионов строк.

def getAllCIKS(filingList):
    cikDICT=defaultdict(int)
    for filing in filingList:
        if filing.startswith('.'):
            del(filing)
            continue
        cik=filing.split('^')[0].strip()
        cikDICT[cik]+=1
        del(filing)
    ciklist=cikDICT.keys()
    ciklist.sort()
return ciklist

allCIKS=getAllCIKS(open(r'c:\filinglist.txt').readlines())

Если я запустлю это вместо этого, я покажу увеличение почти на 400 мб

cikDICT=defaultdict(int)
for filing in open(r'c:\filinglist.txt').readlines():
    if filing.startswith('.'):
        del(filing)
        continue
    cik=filing.split('^')[0].strip()
    cikDICT[cik]+=1
    del(filing)

ciklist=cikDICT.keys()
ciklist.sort()
del(cikDICT)

EDIT Я играл с этим еще немного сегодня. Мои наблюдения и вопросы должны быть немного уточнены, так как я сосредоточился на использовании ПФ. К сожалению, я могу только ткнуть в это между моими другими заданиями. Однако я начинаю задумываться о ссылках и копиях. Если я создаю словарь из списка, содержит ли контейнер словаря копию значений, которые пришли из списка, или они содержат ссылки на значения в списке? Я держу пари, что значения копируются вместо ссылок.

Еще одна вещь, которую я заметил, это то, что элементы в списке GC были элементами из контейнеров, которые были удалены. Имеет ли это смысл? Итак, у меня есть список, и предположим, что каждый из элементов в списке был [(aTuple), anInteger, [другой список]]. Когда я начал изучать, как манипулировать объектами gc и проверять их, я нашел эти объекты в gc, хотя список был принудительно удален, и хотя я передал значения 0,1 и 2 методу, который я не помню чтобы попытаться удалить их.

Я ценю то, что люди делятся своими мыслями. К сожалению, мне всегда интересно выяснить, как все работает под капотом.

Ответы [ 5 ]

3 голосов
/ 28 мая 2009

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

1 голос
/ 28 мая 2009

Вы можете использовать интерфейс сборщика мусора Python , предоставленный для более тщательного изучения того, что (если вообще что-то) осталось во втором случае. В частности, вы можете проверить gc.get_objects () , чтобы увидеть, что осталось невыбранным, или gc.garbage , чтобы узнать, есть ли у вас какие-либо ссылочные циклы.

0 голосов
/ 04 июня 2009

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

объекты, на которые ссылаются словари, похоже, остаются в живых. Я думаю (но не уверен), что процесс выталкивания словаря из функции форсирует процесс копирования и убивает объект. Это не завершено, мне нужно провести еще какое-то исследование.

0 голосов
/ 28 мая 2009

Может быть, вам следует пересмотреть свой код, чтобы избавиться от ненужных переменных (которые могут быть освобождены не сразу) ... как насчет следующего фрагмента?

myfile = file(r"c:\fillinglist.txt")
ciklist = sorted(set(x.split("^")[0].strip() for x in myfile if not x.startswith(".")))

РЕДАКТИРОВАТЬ: Я не знаю, почему этот ответ был признан отрицательным ... Может быть, потому что он короткий? Или может быть потому, что проголосовавший чувак не смог понять, как этот однострочный текст делает то же, что и код в вопросе, не создавая ненужных временных контейнеров?

Вздох ...

0 голосов
/ 28 мая 2009

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

Реальная экономия памяти при создании функций заключается в вашей кратковременной памяти. Перемещая что-либо в функцию, вы уменьшаете количество деталей, которое вам нужно запомнить, инкапсулируя часть мелочей.

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