Полка слишком медленная для больших словарей, что я могу сделать, чтобы улучшить производительность? - PullRequest
13 голосов
/ 19 августа 2010

Я храню таблицу, используя python, и мне нужно постоянство.

По сути, я храню таблицу в виде словарной строки для чисел. И все хранится с полкой

self.DB=shelve.open("%s%sMoleculeLibrary.shelve"%(directory,os.sep),writeback=True) 

Я использую writeback до True, так как обнаружил, что система, как правило, нестабильна, если я этого не сделаю.

После вычислений система должна закрыть базу данных и сохранить ее обратно. Сейчас база данных (таблица) составляет около 540 МБ, и это занимает много времени. Время взорвалось после того, как таблица выросла до 500 МБ. Но мне нужен намного больший стол. На самом деле мне нужно два из них.

Я, вероятно, использую неправильную форму настойчивости. Что я могу сделать, чтобы улучшить производительность?

Ответы [ 4 ]

13 голосов
/ 19 августа 2010

Для хранения большого словаря из string : number пар ключ-значение я бы предложил JSON-собственное решение для хранения, такое как MongoDB .Он имеет прекрасный API для Python, Pymongo .MongoDB сам по себе легкий и невероятно быстрый, а объекты json изначально будут словарями в Python.Это означает, что вы можете использовать ключ string в качестве идентификатора объекта, что обеспечивает сжатое хранилище и быстрый поиск.

В качестве примера того, насколько простым будет код, см. Следующее:

d = {'string1' : 1, 'string2' : 2, 'string3' : 3}
from pymongo import Connection
conn = Connection()
db = conn['example-database']
collection = db['example-collection']
for string, num in d.items():
    collection.save({'_id' : string, 'value' : num})
# testing
newD = {}
for obj in collection.find():
    newD[obj['_id']] = obj['value']
print newD
# output is: {u'string2': 2, u'string3': 3, u'string1': 1}

Вам просто нужно конвертировать обратно из юникода, что тривиально.

10 голосов
/ 22 марта 2013

Исходя из моего опыта, я бы рекомендовал использовать SQLite3 , который поставляется с Python. Он хорошо работает с большими базами данных и номерами ключей. Миллионы ключей и гигабайт данных - это не проблема. Полка полностью впустую в этот момент. Кроме того, наличие отдельного db-процесса не выгодно, просто требуется больше контекстных перестановок. В своих тестах я обнаружил, что SQLite3 был предпочтительным вариантом для локальной обработки больших наборов данных. Запуск локального механизма баз данных, такого как mongo, mysql или postgresql, не дает никаких дополнительных значений и также был медленнее.

1 голос
/ 15 июня 2017

Я думаю, что ваша проблема связана с тем, что вы используете writeback=True. документация гласит (акцент мой):

Из-за семантики Python, полка не может знать, когда изменяемый постоянный словарь изменен. По умолчанию измененные объекты записываются только при назначении на полку (см. пример). Если Необязательный параметр обратной записи имеет значение True, все записи доступны также кэшируется в памяти и записывается обратно в sync () и close (); этот может сделать его более удобным для изменения изменяемых записей в постоянном словарь, но, если доступ ко многим записям, он может потреблять огромные объемы памяти для кэша, и это может сделать операцию закрытия очень медленно, так как все записи, к которым получен доступ, записываются обратно (нет способа чтобы определить, какие записи были изменены, а какие были на самом деле мутировал).

Вы можете избежать использования writeback=True и убедиться, что данные записываются только один раз (обратите внимание, что последующие изменения будут потеряны).

Если вы считаете, что это неправильный вариант хранения (трудно сказать, не зная, как структурированы данные), я предлагаю sqlite3, он интегрирован в python (таким образом, очень переносим) и имеет очень хорошие характеристики. Это несколько сложнее, чем простое хранилище значений ключей.

См. Другие ответы для альтернатив.

1 голос
/ 19 августа 2010

Насколько больше?Каковы шаблоны доступа?Какие виды вычислений вам нужно выполнить для этого?

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

Возможно, вы захотите взглянуть на SQLAlchemy или напрямую использовать что-то вроде bsddb, но оба они пожертвуют простотой кода.Тем не менее, с помощью SQL вы можете разгрузить часть работы на уровень базы данных в зависимости от рабочей нагрузки.

...