Ядро умирает после команды itertools.combination - PullRequest
0 голосов
/ 03 июля 2018

я использую Python 3.5.2 | Anaconda 4.3.0 (x86_64) | (по умолчанию, 2 июля 2016 г., 17:52:12) [GCC 4.2.1 Совместимый Apple LLVM 4.2 (clang-425.0.28)]

Я должен выполнить следующую команду

longList = list(combinations(range(2134), 3))

Я знаю, что длина составляет около 1,6 миллиарда. Когда я запускаю его, через некоторое время появляется сообщение «Ядро, кажется, умерло. Оно автоматически перезапустится».

Та же команда с 3 вместо 2 запускается без проблем:

longList = list(combinations(range(2134), 2))

Что я могу / должен сделать в этом случае?

1 Ответ

0 голосов
/ 04 июля 2018

Вероятно, вам не хватает памяти. Быстрый расчет: 64-разрядный тип int или указатель имеет размер 8 байт. У вас есть 1,6 миллиарда комбинаций, которые являются кортежами. Каждый кортеж содержит три целых числа. Это означает, что вам потребуется не менее 1,6E9 * (1 + 3) * 8B = 48 ГБ памяти.

Однако из-за модели памяти Python вам понадобится во много раз больше: каждое целое на самом деле является объектом, поэтому нам нужно 1 машинное слово для указателя в списке и, возможно, 3 или 4 машинных слова для самого объекта (Я не уверен в деталях, прочитайте исходный код CPython для фактического расположения объекта). Объект кортежа также будет иметь накладные расходы. Я предполагаю, что у каждого объекта есть два слова. Таким образом, мы должны добавить дополнительные 1,6E9 * (3 + 1) * 2 * 8B = 95 ГБ дополнительных служебных данных, в общей сложности около 143 ГБ.

Этого можно избежать, используя плотный массив NumPy, поскольку он использует реальные целые числа, а не объекты. Это устраняет все накладные расходы от целочисленных и кортежных объектов, так что нам «всего лишь» нужно 1.6E9 * 3 * 8B = 35 ГБ.

Я полагаю, вы не используете оборудование с таким большим объемом памяти.

Ваш вызов combinations(..., 2) не является проблемой, поскольку он генерирует только около 2 миллионов кортежей, которые имеют требования к памяти в диапазоне мегабайт (2,2E6 * (1 + 4 + 2 * 3) * 8B = 180 МБ). В качестве массива numpy нам нужно только 2.2E6 * 2 * 8B = 33 МБ.

Так в чем же здесь решение?

  • В масштабе, детали низкого уровня, такие как модели памяти, очень важны даже для Python
  • Использование numpy может значительно сократить использование памяти, как правило, в 4 раза. Больше, если вы используете меньшие типы, например, dtype='int16' будет дополнительным фактором уменьшения в 4 раза.
  • Подумайте, нужно ли вам с нетерпением преобразовывать combinations() в список, или вы можете использовать итератор лениво или небольшими кусками
...