Ручное управление сборкой мусора вызывает KeyErrors при использовании Python внутри Azure Function

Вопрос или проблема

У меня есть скрипт на Python, который я загружаю в Azure Function App (это триггер для blob storage). Моя функция время от времени достигает предела по памяти, и я подумал, что неплохо было бы вручную выполнить сборку мусора в конце скрипта, чтобы посмотреть, поможет ли это мне избежать превышения лимита. Вот что у меня сейчас в конце скрипта.

        del blob_data_frame
        del processed_df
        if blob_data_frame1:
            del blob_data_frame1
        if blob_data_frame2:
            del blob_data_frame2

        for name in dir():
            if not name.startswith(('_', 'blob', 'conn', 'engine_', 'myblob', 'params', 'processed_df', 'result')):
                del globals()[name]

        for name in dir():
            if not name.startswith(('_', 'blob', 'conn', 'engine_', 'myblob', 'params', 'processed_df', 'result')):
                del locals()[name]  

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

Исключение: KeyError: {переменная}

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

ПРАЗДНИК ДЛЯ БОЛЬШОЙ ЯСНОСТИ:
Ошибка возникает из строки del globals()[name].

Здесь ваша ошибка заключается в том, что вашего ключа не существует в globals. Что-то вроде этого решит вашу ошибку:

del blob_data_frame
del processed_df
if blob_data_frame1:
    del blob_data_frame1
if blob_data_frame2:
    del blob_data_frame2

for name in dir():
    if globals().get(name) and not name.startswith(('_', 'blob', 'conn', 'engine_', 'myblob', 'params', 'processed_df', 'result')):
        del globals()[name]

for name in dir():
    if locals().get(name) and not name.startswith(('_', 'blob', 'conn', 'engine_', 'myblob', 'params', 'processed_df', 'result')):
        del locals()[name]  

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

Ответ или решение

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

Вот несколько подходов для решения этой проблемы и уменьшения использования памяти в вашей Azure Function:

Решение 1: Удаление с проверкой наличия ключа

Вместо непосредственного удаления переменной через del globals()[name], вы можете использовать метод get(), который позволит избежать возникновения ошибки, если переменной не существует:

if 'blob_data_frame' in globals():
    del globals()['blob_data_frame']
if 'processed_df' in globals():
    del globals()['processed_df']
if 'blob_data_frame1' in globals():
    del globals()['blob_data_frame1']
if 'blob_data_frame2' in globals():
    del globals()['blob_data_frame2']

for name in dir():
    if name not in ('blob', 'conn', 'engine_', 'myblob', 'params', 'processed_df', 'result') and not name.startswith('_'):
        if name in globals():
            del globals()[name]

Решение 2: Использование gc.collect()

Вы можете также рассмотреть возможность использования модуля gc (garbage collection) для управления памятью. Он позволяет вам явно вызывать сборщик мусора, что может также помочь в некоторых ситуациях:

import gc

# Ваш код

# Явный вызов сборщика мусора
gc.collect()

Решение 3: Упрощение управления переменными

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

Рекомендации

  1. Анализируйте использование памяти с помощью профайлеров, таких как memory_profiler, чтобы понять, где возникают утечки памяти.
  2. Используйте Lazy Evaluation, чтобы задачи, не требующие немедленного вычисления, оставались без обработки до тех пор, пока это не станет необходимо.
  3. Избегайте глобальных переменных, если это возможно, и используйте функции и классы для большей инкапсуляции.

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

Оцените материал
Добавить комментарий

Капча загружается...