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

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

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

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

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

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

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

4 ответа

Для хранения большого словаря 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}

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

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам