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

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

Каковы наилучшие параметры загрузки файлов (скорость и выход)?

Просто нужно хранить простой список чисел. нет необходимости в случайном доступе N-го элемента, просто операции добавления/поп-типа.

Ответ 1

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

I.e., в основном, предполагая, например, unsigned-long числа, что-то вроде:

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 действительно все, что вам нужно, это должно служить.

Ответ 2

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

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

Ответ 3

Ответ очень "зависит".

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

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

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

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

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

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

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

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

Ответ 4

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

Ответ 6

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

Ответ 7

Современные операционные системы справятся с этим для вас, не беспокоясь об этом. Он назывался виртуальная память.

Ответ 8

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

Ответ 9

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

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