Рассол или json?

115

Мне нужно сохранить на диск небольшой dictобъект, ключи которого имеют тип, strа значения - ints, а затем восстановить его . Что-то вроде этого:

{'juanjo': 2, 'pedro':99, 'other': 333}

Какой вариант лучше и почему? Сериализовать его с помощью pickleили с помощью simplejson?

Я использую Python 2.6.

Хуанхо Конти
источник
преобразовать во что? И в каком смысле лучше ?
SilentGhost,
10
В 2.6 вы бы не использовали simplejson, вы бы использовали встроенный jsonмодуль (у которого точно такой же интерфейс).
Майк Грэм,
5
"Лучший"? Лучше всего для чего? Скорость? Сложность? Гибкость? Стоимость?
S.Lott
см. также stackoverflow.com/questions/8968884/…
Триларион
@Trilarion: YAML - это надмножество JSON
Мартин Тома,

Ответы:

69

Если у вас нет требований к совместимости (например, вы просто собираетесь использовать данные с Python) и двоичный формат подходит, используйте cPickle, который дает вам действительно быструю сериализацию объектов Python.

Если вам нужна совместимость или вам нужен текстовый формат для хранения ваших данных, используйте JSON (или другой подходящий формат в зависимости от ваших ограничений).

Håvard S
источник
48
JSON кажется быстрее, чем cPickle.
mac,
5
Мой ответ подчеркивает те проблемы, которые я считаю наиболее важными при выборе любого из решений. Я не утверждаю, что один из них быстрее другого. Если JSON быстрее и подходит, используйте JSON! (То есть, нет причин для вашего отрицательного голосования.)
Håvard S
10
Я хочу сказать: нет реальной причины для использования cPickle(или pickle) в зависимости от вашего помещения через JSON. Когда я впервые прочитал ваш ответ, я подумал, что причина могла быть в скорости, но поскольку это не так ... :)
Mac
14
Тест, цитируемый @mac, проверяет только строки. Я тестировал str, int и float по отдельности и обнаружил, что json медленнее, чем cPickle с сериализацией float, но быстрее с десериализацией float. Для int (и str) json быстрее в обоих направлениях. Данные и код: gist.github.com/marians/f1314446b8bf4d34e782
Marian
24
Последний протокол cPickle теперь быстрее, чем JSON. Проголосовавший за то, что JSON работает быстрее, устарел на несколько лет. stackoverflow.com/a/39607169/1007353
JDiMatteo
105

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

Майк Грэм
источник
Спасибо. Все равно буду сбрасывать и загружать в одной программе.
Juanjo Conti,
2
Хотя в текущем приложении риски безопасности могут быть низкими, JSON позволяет полностью закрыть все.
Майк Грэм,
4
Можно создать рассол-вирус, который встраивается во все, что маринуется после загрузки. С json это невозможно.
User
2
Помимо безопасности, у JSON есть дополнительное преимущество, заключающееся в том, что он упрощает миграцию, так что вы можете загружать данные, которые были сохранены более старой версией вашего приложения. Тем временем вы могли добавить поле или заменить целую подструктуру. Написать такой конвертер (миграцию) для dict / list очень просто, но с Pickle вам будет сложно загрузить его, прежде чем вы даже сможете подумать о преобразовании.
ВОГ
2
Я не думал об этом аспекте (безопасность и способность маринованных объектов запускать произвольный код). Спасибо что подметил это!
CaffeinatedMike
43

Вы также можете найти это интересным с некоторыми диаграммами для сравнения: http://kovshenin.com/archives/pickle-vs-json-which-is-faster/

КОВШЕНИН
источник
1
В статье сравнивается производительность только для струнных. Вот сценарий, который вы можете запустить, чтобы тестировать строки, числа с плавающей запятой и целые числа по отдельности: gist.github.com/marians/f1314446b8bf4d34e782
Marian
20

Если вас в первую очередь заботят скорость и пространство, используйте cPickle, потому что cPickle быстрее, чем JSON.

Если вас больше интересует совместимость, безопасность и / или удобочитаемость, используйте JSON.


Результаты тестов, упомянутые в других ответах, были записаны в 2010 году, а обновленные тесты в 2016 году с протоколом cPickle 2 показывают:

  • cPickle загрузка в 3,8 раза быстрее
  • cPickle в 1,5 раза быстрее читает
  • cPickle немного меньшая кодировка

Воспроизведите это самостоятельно с помощью этой сути , которая основана на тесте Konstantin, упомянутом в других ответах, но с использованием cPickle с протоколом 2 вместо pickle и с использованием json вместо simplejson (поскольку json быстрее, чем simplejson ), например

wget https://gist.github.com/jdimatteo/af317ef24ccf1b3fa91f4399902bb534/raw/03e8dbab11b5605bc572bc117c8ac34cfa959a70/pickle_vs_json.py
python pickle_vs_json.py

Результаты с python 2.7 на достойном процессоре Xeon 2015 года:

Dir Entries Method  Time    Length

dump    10  JSON    0.017   1484510
load    10  JSON    0.375   -
dump    10  Pickle  0.011   1428790
load    10  Pickle  0.098   -
dump    20  JSON    0.036   2969020
load    20  JSON    1.498   -
dump    20  Pickle  0.022   2857580
load    20  Pickle  0.394   -
dump    50  JSON    0.079   7422550
load    50  JSON    9.485   -
dump    50  Pickle  0.055   7143950
load    50  Pickle  2.518   -
dump    100 JSON    0.165   14845100
load    100 JSON    37.730  -
dump    100 Pickle  0.107   14287900
load    100 Pickle  9.907   -

Python 3.4 с протоколом pickle 3 работает еще быстрее.

JDiMatteo
источник
11

JSON или рассол? Как насчет JSON и рассола! Вы можете использовать jsonpickle. Он прост в использовании, и файл на диске доступен для чтения, потому что это JSON.

http://jsonpickle.github.com/

Пол Хильдебрандт
источник
2
Кто-нибудь сравнивал его производительность с опциями? Сравним ли он по производительности с необработанным json, как показано здесь benfrederickson.com/dont-pickle-your-data ?
Josep Valls,
Это не широкий тест, но у меня была существующая игра, в которой уровни сохранялись с помощью pickle (python3). Я хотел попробовать jsonpickle для удобства чтения, но, к сожалению, сохранение уровней было намного медленнее. 1597 мс для jsonpickle и 88 мс или обычного pickle при сохранении уровня. Для уровня загрузки 1604 мс для jsonpickle и 388 для рассола. Жалко, как мне нравятся читабельные сейвы.
Нил МакГилл
Я тестировал это в нашей торговой системе, читаемость дает примерно двукратное снижение скорости сериализации + десериализации по сравнению с pickle. Хотя отлично подходит для всего остального.
nurettin
6

Я попробовал несколько методов и обнаружил, что использование cPickle с установкой аргумента протокола метода дампа как: cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)является самым быстрым методом дампа.

import msgpack
import json
import pickle
import timeit
import cPickle
import numpy as np

num_tests = 10

obj = np.random.normal(0.5, 1, [240, 320, 3])

command = 'pickle.dumps(obj)'
setup = 'from __main__ import pickle, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("pickle:  %f seconds" % result)

command = 'cPickle.dumps(obj)'
setup = 'from __main__ import cPickle, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("cPickle:   %f seconds" % result)


command = 'cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)'
setup = 'from __main__ import cPickle, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("cPickle highest:   %f seconds" % result)

command = 'json.dumps(obj.tolist())'
setup = 'from __main__ import json, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("json:   %f seconds" % result)


command = 'msgpack.packb(obj.tolist())'
setup = 'from __main__ import msgpack, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("msgpack:   %f seconds" % result)

Вывод:

pickle         :   0.847938 seconds
cPickle        :   0.810384 seconds
cPickle highest:   0.004283 seconds
json           :   1.769215 seconds
msgpack        :   0.270886 seconds
Ахмед Абобакр
источник
4

Лично я обычно предпочитаю JSON, потому что данные удобочитаемы . Определенно, если вам нужно сериализовать что-то, что JSON не примет, используйте pickle.

Но для большинства хранилищ данных вам не нужно сериализовать что-либо странное, а JSON намного проще и всегда позволяет вам открыть его в текстовом редакторе и самостоятельно проверить данные.

Скорость хорошая, но для большинства наборов данных разница незначительна; В любом случае Python обычно не слишком быстр.

риккнаги
источник
1
Правда. Но для 100элементов в списке человеческому глазу разница совершенно незначительна. Определенно иначе при работе с большими наборами данных.
rickcnagy