Альтернативы хранению больших списков в памяти (python)

Если у меня есть список(или массив, словарь....) в python, который может превышать доступное адресное пространство памяти (32 бит python), каковы параметры и относительные скорости? (кроме того, что не делает список таким большим) Список может превысьте память, но у меня нет способа узнать это раньше. Как только он начнет превышать 75%, я хотел бы больше не хранить список в памяти (или новые элементы в любом случае), есть ли способ конвертировать в файловый подход на середине потока?

каковы наилучшие (скорость входа и выхода) варианты хранения файлов?

просто нужно сохранить простой список чисел. нет необходимости в случайном доступе к элементам Nth, просто добавьте операции типа pop.

9 ответов


если ваши "числа" достаточно просты (целые числа со знаком или без знака до 4 байт каждый или поплавки по 4 или 8 байт каждый), я рекомендую стандартную библиотеку массив модуль как лучший способ сохранить несколько миллионов из них в памяти ("наконечник "вашего" виртуального массива") с двоичным файлом (открытым для двоичного R/W), поддерживающим остальную часть структуры на диске. array.array очень быстро fromfile и tofile методы для облегчения перемещения данных далее.

то есть, в принципе, предполагая, например, беззнаковые длинные числа, что-то вроде:

import os

# no more than 100 million items in memory at a time
MAXINMEM = int(1e8)

class bigarray(object):
  def __init__(self):
    self.f = open('afile.dat', 'w+')
    self.a = array.array('L')
  def append(self, n):
    self.a.append(n)
    if len(self.a) > MAXINMEM:
      self.a.tofile(self.f)
      del self.a[:]
  def pop(self):
    if not len(self.a):
      try: self.f.seek(-self.a.itemsize * MAXINMEM, os.SEEK_END)
      except IOError: return self.a.pop()  # ensure normal IndexError &c
      try: self.a.fromfile(self.f, MAXINMEM)
      except EOFError: pass
      self.f.seek(-self.a.itemsize * MAXINMEM, os.SEEK_END)
      self.f.truncate()
    return self.a.pop()

конечно вы можете добавить и другие методы по мере необходимости (например, отслеживать общую длину, добавить extend, все, что угодно), а если pop и append действительно все, что вам нужно это должно служить.


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

одна из возможностей-структурировать ваши данные относительно и хранить их в базе данных SQLite.


ответ очень много "это зависит".

Что вы храните в списках? Струны? целые числа? Объекты?

Как часто список записывается по сравнению с чтением? Элементы добавляются только в конце или могут быть изменены или вставлены посередине?

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

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

Если вы хотите поведение словаря, то посмотрите на модули db-dbm, gdbm,bsddb и т. д.

Если вы хотите писать произвольный доступ, возможно, база данных SQL может быть лучше.

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

edit: Из ваших обновленных требований я бы пошел с плоским файлом и сохранил буфер в памяти последних N элементов.


Ну, если вы ищете скорость, и ваши данные являются числовыми по своей природе, вы можете рассмотреть возможность использования numpy и PyTables или h5py. Из того, что я помню, интерфейс не так хорош, как простые списки, но масштабируемость фантастическая!


вы проверили модуль python shelve, который основан на рассоле?

http://docs.python.org/library/shelve.html


вы можете рассмотреть другую структуру: не список, но выяснить, как это сделать (ваша задача) с генератором или пользовательским итератором.


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


Как насчет базы данных, ориентированной на документ?
Есть несколько альтернатив; я думаю, что самый известный в настоящее время CouchDB, но вы также можете пойти на Токио Шкаф или MongoDB. Последний имеет преимущество Привязок python непосредственно из основного проекта, не требуя дополнительного модуля.


вы можете попробовать blist: https://pypi.python.org/pypi/blist/

blist-это замена списка Python, обеспечивающая лучшую производительность при изменении больших списков.