Потребление памяти модулем полки Python

Мне было поручено прочитать файл .txt, который представляет собой журнал различных событий, и записать некоторые из этих событий в словарь.

Проблема в том, что размер файла иногда может превышать 3 ГБ. Это означает, что словарь становится слишком большим, чтобы поместиться в основную память. Кажется, что Shelve — хороший способ решить эту проблему. Однако, поскольку я буду постоянно изменять словарь, у меня должна быть включена опция writeback. Это то, что меня беспокоит - в учебнике говорится, что это замедлит процесс чтения/записи и будет использовать больше памяти, но я не могу найти статистику о том, как это влияет на скорость и память.

Может ли кто-нибудь уточнить, насколько это влияет на скорость чтения/записи и память, чтобы я мог решить, использовать ли опцию обратной записи или пожертвовать некоторой читаемостью ради эффективности кода?

Спасибо


person inspectorG4dget    schedule 24.05.2011    source источник
comment
Это зависит от того, что вы делаете со словарем: если вам нужно только изменить его, заменив значения (shelf['key'] = newvalue), вам не нужна обратная запись. Если вы изменяете в нем изменяемые типы (shelf['key'].append(x), вам нужна обратная запись. Конечно, вы можете отключить обратную запись и всегда помнить об изменении и замене значений на своей полке, если хотите.   -  person Thomas K    schedule 24.05.2011
comment
Мне нужно только добавить пары ключ-значение. Но так как я работаю с вложенными словарями, я буду добавлять пары k,v и во внутренние словари.   -  person inspectorG4dget    schedule 24.05.2011
comment
Можете ли вы написать его так, чтобы вы всегда брали значение с полки, добавляли к нему на любом уровне, а затем возвращали на полку?   -  person Thomas K    schedule 24.05.2011
comment
Будет ли это так, как показано в учебнике, в котором используется переменная temp   -  person inspectorG4dget    schedule 24.05.2011
comment
Это то, чего я стараюсь избегать. Я могу сделать это, если у меня есть том, но я хотел бы избежать этого, насколько это возможно - отсюда и вся проблема с обратной записью. Мысли?   -  person inspectorG4dget    schedule 25.05.2011
comment
Взгляните на исходный код: svn.python.org/view/python/branches/release27-maint/Lib/ Короче говоря, он будет хранить в памяти все, к чему вы прикасаетесь, пока вы не вызовете .sync(), после чего он перезаписывается на диск и освобождается. Таким образом, попадание зависит от того, по какому шаблону вы обращаетесь к файлу.   -  person Thomas K    schedule 25.05.2011
comment
Я знаю, что это не отвечает на ваш вопрос, но для данных такого масштаба, возможно, стоит поискать другое встроенное хранилище документов. Может анклийт?   -  person bsa    schedule 02.05.2015


Ответы (1)


Для баз данных такого размера полка действительно не подходит. Если вам не нужна высокодоступная архитектура клиент/сервер, и вы просто хотите преобразовать файл TXT в локальную базу данных с доступом в памяти, вам действительно следует использовать ZODB

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

Вот простой пример того, как преобразовать вашу базу данных полки в базу данных ZODB, которая решит ваши проблемы с использованием памяти / производительностью.

#!/usr/bin/env python
import shelve
import ZODB, ZODB.FileStorage
import transaction
from optparse import OptionParser
import os
import sys
import re

reload(sys)
sys.setdefaultencoding("utf-8")

parser = OptionParser()

parser.add_option("-o", "--output", dest = "out_file", default = False, help ="original shelve database filename")
parser.add_option("-i", "--input", dest = "in_file", default = False, help ="new zodb database filename")

parser.set_defaults()
options, args = parser.parse_args()

if options.in_file == False or options.out_file == False :
    print "Need input and output database filenames"
    exit(1)

db = shelve.open(options.in_file, writeback=True)
zstorage = ZODB.FileStorage.FileStorage(options.out_file)
zdb = ZODB.DB(zstorage)
zconnection = zdb.open()
newdb = zconnection.root()

for key, value in db.iteritems() :
    print "Copying key: " + str(key)
    newdb[key] = value
                                                                                                                                                                                                
transaction.commit() 

person Michael Galaxy    schedule 30.05.2015