Альтернативы хранению больших списков в памяти (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 элементов.
вы можете рассмотреть другую структуру: не список, но выяснить, как это сделать (ваша задача) с генератором или пользовательским итератором.
современные операционные системы будут обрабатывать это для вас без необходимости беспокоиться об этом. Это называется виртуальный.
Как насчет базы данных, ориентированной на документ?
Есть несколько альтернатив; я думаю, что самый известный в настоящее время CouchDB, но вы также можете пойти на Токио Шкаф или MongoDB. Последний имеет преимущество Привязок python непосредственно из основного проекта, не требуя дополнительного модуля.
вы можете попробовать blist: https://pypi.python.org/pypi/blist/
blist-это замена списка Python, обеспечивающая лучшую производительность при изменении больших списков.