Вопрос или проблема
У меня есть скрипт на 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 и их последующего удаления, старайтесь замещать их на этапе обработки, что поможет снизить распределение памяти.
Рекомендации
- Анализируйте использование памяти с помощью профайлеров, таких как
memory_profiler
, чтобы понять, где возникают утечки памяти. - Используйте Lazy Evaluation, чтобы задачи, не требующие немедленного вычисления, оставались без обработки до тех пор, пока это не станет необходимо.
- Избегайте глобальных переменных, если это возможно, и используйте функции и классы для большей инкапсуляции.
Следуя перечисленным рекомендациям, вы сможете уменьшить вероятность возникновения ошибок и улучшить управление памятью в вашем Azure Function.