Рубрики
Без рубрики

Уменьшение потребления памяти в Python с использованием генераторов

Вам когда-нибудь приходилось обработать большой набор данных и столкнулся с ужасным CreadError в Python, или … с меткой Python.

Вам когда-нибудь приходилось обработать большой набор данных и столкнулся с страшным Memoryerror в Python или просто нужно для ограничения потребления памяти большого набора данных? Если ответ на это да, рассмотрите возможность использования генератора.

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

Генератор по их ядру – это функции, которые возвращают итератор, что означает, что генератор может быть обработан. Однако в отличие от обычного итератора в Python, весь набор данных не загружается в фронт памяти.

Создание функции генератора

Функции генератора вращаются вокруг доходность Заявление ( больше на что позже ). Они определяются как нормальная функция, с добавлением доходность заявление на месте знакомого вернуть Отказ

В приведенном ниже ( надуманный ) Пример, функция генератора basic_generator определено. Это вернет генератор, который принесет целые числа до 50 000 000 один за раз.

Генератор, возвращенный basic_generator назначается переменной Ген которые затем могут быть переданы как обычный итератор. Разница здесь заключается в том, что генератор производит одно значение одновременно, а не загрузка всех 50 000 000 целых чисел в память, в качестве списка.

Чтение больших файлов

Вероятно, самое распространенное использование функций генератора является при чтении больших файлов, чтение файла в Python обычно читают все содержимое файла в память одновременно. При работе с большими файлами это может быть проблематично, либо потребляя чрезмерных объемов памяти или в худшем случае, потребляющих сценариев все Доступная память, поднимая Memoryerror И в конечном итоге разбивается приложение.

Примечание. При использовании 32-битной версии Python только 2 ГБ памяти будет рассматриваться в процессе Python, поэтому независимо от того, насколько доступна физическая память, ModelRor будет поднят как только после того, как 2 ГБ потребляется Python.

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

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

Теперь в случае файла, который нужно прочитать в n Оставленные кусочки байтов, можно использовать следующую функцию генератора. Это откроет файл и доходность данных, равных chunk_size Байты.

Создание последовательности

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

Бесконечная числа последовательности

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

Последовательность фибоначчи

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

Выражения генератора

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

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

Под капотом

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

Генераторные объекты хранилищ состояния с использованием внутреннего F_LOCALS Переменные. Кроме того, объект имеет Далее () Метод, который вызывает и запускает код внутри генератора, вплоть до оператора дохода, в результате чего возвращается значение значение, текущее состояние хранится, и выполнение функции приостановлено до другого вызова на Далее () сделан.

Следующий способ можно назвать вручную или неявно в конструкции петли.

Когда значения генераторов исчерпаны A Заставка Исключение поднимается для сигнала сигнала, чтобы генератор был исчерпан, и дополнительные значения не могут быть получены. Это исключение обрабатывается автоматически автоматически по конструкции петли, такого как CONOR CONOP, однако, если вручную призывающую к генератору это исключение необходимо поймать и обрабатываться вручную.

Метрики памяти и производительности

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

В следующем примере размер в байтах генератора для генерации последовательности 50 000 целых чисел сравнивается с статическим списком 50 000 целых чисел. Генератор потребляет только 112 байтов памяти, по сравнению с статически созданным списком целых чисел, которые потребляют 406 488 байтов памяти. В этом конкретном примере генератор ~ 3600x больше эффективен памяти, чем список.

Недостаток этой эффективности памяти, однако, наблюдается с помощью производительности времени выполнения, используя генератор, в отличие от статически сгенерированного списка значений, возникает гораздо более высокое количество вызовов функций и, следовательно, более длительное время выполнения. Ниже простого сумма целых чисел до 100 000 человек профилируется с использованием CPROFILE Отказ Выражение выражения генератора приводит к 100005 функциональным вызовам в 123 мс, по сравнению с пониманием списка, которая занимает только 5 вызовов функций в 12 мс.

Смотрите мой пост на профилирование в Python здесь Отказ

Это связано с генератором, возвращаемым выражением генератора, вызов Далее () Чтобы получить все значения в последовательности.

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

Оригинал: “https://dev.to/lachlaneagling/reducing-memory-consumption-in-python-using-generators-3m8m”