Альтернативы хранению больших списков в памяти (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. Из того, что я помню, интерфейс не так хорош, как простые списки, но масштабируемость фантастична!
Ответ 5
Вы проверяли модуль shelved python, основанный на рассоле?
http://docs.python.org/library/shelve.html
Ответ 6
Возможно, вам захочется рассмотреть другую структуру: не список, а выяснить, как это сделать (ваша задача) с генератором или пользовательским итератором.
Ответ 7
Современные операционные системы справятся с этим для вас, не беспокоясь об этом. Он назывался виртуальная память.
Ответ 8
Как насчет базы данных, ориентированной на документ?
Существует несколько альтернатив; Я думаю, что самый известный в настоящее время CouchDB, но вы также можете пойти на Tokyo Cabinet или MongoDB. Последнее имеет преимущество связывания python непосредственно из основного проекта, не требуя дополнительного модуля.
Ответ 9
Вы можете попробовать blist:
https://pypi.python.org/pypi/blist/
Blist - это замена для списка Python, обеспечивающая лучшую производительность при изменении больших списков.