Самый быстрый способ хранения больших файлов в Python

I недавно задал вопрос о том, как сохранить большие объекты python в файл. Раньше у меня возникали проблемы с преобразованием массивных словарей Python в строку и их запись в файл через write(). Теперь я использую рассол. Хотя он работает, файлы невероятно большие ( > 5 ГБ). У меня мало опыта в таких больших файлах. Я хотел знать, будет ли быстрее или даже возможно застегнуть этот файл pickle до его хранения в памяти.

Ответ 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 и С++ хорошо поддерживаются.