I недавно задал вопрос о том, как сохранить большие объекты python в файл. Раньше у меня возникали проблемы с преобразованием массивных словарей Python в строку и их запись в файл через write()
. Теперь я использую рассол. Хотя он работает, файлы невероятно большие ( > 5 ГБ). У меня мало опыта в таких больших файлах. Я хотел знать, будет ли быстрее или даже возможно застегнуть этот файл pickle до его хранения в памяти.
Самый быстрый способ хранения больших файлов в Python
Ответ 1
Код Python будет чрезвычайно медленным, когда дело доходит до внедрения сериализации данных. Если вы попытаетесь создать эквивалент Pickle в чистом Python, вы увидите, что он будет очень медленным. К счастью, встроенные модули, которые выполняют это довольно неплохо.
Помимо cPickle
, вы найдете модуль marshal
, который намного быстрее.
Но ему нужен реальный дескриптор файла (не из файлового объекта).
Вы можете import marshal as Pickle
и увидеть разницу.
Я не думаю, что вы можете сделать собственный сериализатор, который намного быстрее, чем этот...
Здесь фактический (не настолько старый) серьезный тест сериализаторов Python
Ответ 2
Вы можете сжать данные с помощью bzip2:
from __future__ import with_statement # Only for Python 2.5
import bz2,json,contextlib
hugeData = {'key': {'x': 1, 'y':2}}
with contextlib.closing(bz2.BZ2File('data.json.bz2', 'wb')) as f:
json.dump(hugeData, f)
Загрузите его следующим образом:
from __future__ import with_statement # Only for Python 2.5
import bz2,json,contextlib
with contextlib.closing(bz2.BZ2File('data.json.bz2', 'rb')) as f:
hugeData = json.load(f)
Вы также можете сжать данные с помощью zlib или gzip с почти таким же интерфейсом. Однако скорость сжатия zlib и gzip будет ниже, чем при использовании bzip2 (или lzma).
Ответ 3
быстрее или даже возможно застегнуть этот файл рассола до [записи]
Конечно, это возможно, но нет причин пытаться сделать явную застегнутую копию в памяти (она может не соответствовать!), прежде чем писать ее, когда вы можете автоматически заставить ее зашифровать, поскольку она написана, в стандартных библиотечных функциях;)
См. http://docs.python.org/library/gzip.html. В принципе, вы создаете особый вид потока с помощью
gzip.GzipFile("output file name", "wb")
а затем используйте его точно как обычный file
, созданный с помощью open(...)
(или file(...)
, если на то пошло).
Ответ 4
Я бы просто расширил phihag-ответ.
При попытке сериализации объекта, приближающегося к размеру ОЗУ, следует избегать pickle/cPickle, так как требует дополнительной памяти В 1-2 раза больше размера объекта для сериализации. Это правда даже при потоковой передаче в BZ2File. В моем случае у меня даже не было места подкачки.
Но проблема с JSON (и аналогично файлам HDF, упомянутым в связанной статье) заключается в том, что она не может сериализовать кортежи, которые в моих данных используются как ключи к dicts. Для этого нет большого решения; лучшее, что я мог найти, это преобразовать кортежи в строки, что требует некоторой собственной памяти, но гораздо меньше, чем рассол. В настоящее время вы также можете использовать библиотеку ujson, которая намного быстрее, чем библиотека json.
Для кортежей, состоящих из строк (требуется, чтобы строки не содержали запятых):
import ujson as json
from bz2 import BZ2File
bigdata = { ('a','b','c') : 25, ('d','e') : 13 }
bigdata = dict([(','.join(k), v) for k, v in bigdata.viewitems()])
f = BZ2File('filename.json.bz2',mode='wb')
json.dump(bigdata,f)
f.close()
Чтобы перекомпилировать кортежи:
bigdata = dict([(tuple(k.split(',')),v) for k,v in bigdata.viewitems()])
Альтернативно, если, например, ваши ключи являются 2-х целыми целыми числами:
bigdata2 = { (1,2): 1.2, (2,3): 3.4}
bigdata2 = dict([('%d,%d' % k, v) for k, v in bigdata2.viewitems()])
# ... save, load ...
bigdata2 = dict([(tuple(map(int,k.split(','))),v) for k,v in bigdata2.viewitems()])
Другим преимуществом такого подхода к рассолу является то, что json, по-видимому, сжимает значительно лучше, чем рассолы при использовании сжатия bzip2.
Ответ 5
Посмотрите на Google ProtoBuffers. Хотя они не предназначены для больших файлов из коробки, таких как аудио-видеофайлы, они преуспевают в сериализации объектов, как в вашем случае, потому что они были предназначены для этого. Практика показывает, что в какой-то момент вам может понадобиться обновить структуру ваших файлов, и ProtoBuffers справятся с ней. Кроме того, они очень оптимизированы для сжатия и скорости. И вы не привязаны к Python, Java и С++ хорошо поддерживаются.