Pickle czy JSON?

114

Muszę zapisać na dysku mały dictobiekt, którego klucze są typu stri wartości ints, a następnie odzyskać go . Coś takiego:

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

Jaka jest najlepsza opcja i dlaczego? Serializować go z pickleczy z simplejson?

Używam Pythona 2.6.

Juanjo Conti
źródło
przekonwertować to na co? W jakim sensie lepiej ?
SilentGhost
10
W 2.6 byś nie używał simplejson, użyłbyś wbudowanego jsonmodułu (który ma dokładnie taki sam interfejs).
Mike Graham
5
"Najlepsza"? Najlepsze do czego? Prędkość? Złożoność? Elastyczność? Koszt?
S.Lott,
zobacz także stackoverflow.com/questions/8968884/…
Trilarion
@Trilarion: YAML to
Martin Thoma

Odpowiedzi:

68

Jeśli nie masz żadnych wymagań dotyczących interoperacyjności (np. Zamierzasz po prostu używać danych w Pythonie) i format binarny jest w porządku, wybierz cPickle, który zapewnia naprawdę szybką serializację obiektów Pythona.

Jeśli chcesz współdziałania lub chcesz mieć format tekstowy do przechowywania danych, wybierz JSON (lub inny odpowiedni format w zależności od ograniczeń).

Håvard S
źródło
48
Wydaje się, że JSON jest szybszy niż cPickle.
mac
5
Moja odpowiedź zwraca uwagę na obawy, które moim zdaniem są najważniejsze do rozważenia przy wyborze jednego z rozwiązań. Nie twierdzę, że któryś z nich jest szybszy od drugiego. Jeśli JSON jest szybszy I w inny sposób odpowiedni, idź z JSON! (Tj. Nie ma powodu, aby głosować
przeciw
10
Chodzi mi o to: nie ma prawdziwego powodu, aby używać cPickle(lub pickle) w oparciu o twoje przesłanki przez JSON. Kiedy po raz pierwszy przeczytałem twoją odpowiedź, pomyślałem, że powodem może być szybkość, ale ponieważ tak nie jest ... :)
mac
14
Test porównawczy cytowany przez @mac testuje tylko ciągi. Testowałem osobno str, int i float i odkryłem, że json jest wolniejszy niż cPickle z serializacją typu float, ale szybszy z unerialization float. W przypadku int (i str) json jest szybszy w obie strony. Dane i kod: gist.github.com/marians/f1314446b8bf4d34e782
Marian
24
Najnowszy protokół cPickle jest teraz szybszy niż JSON. Głosowany w górę komentarz dotyczący szybszego JSON jest nieaktualny o kilka lat. stackoverflow.com/a/39607169/1007353
JDiMatteo
104

Wolę JSON niż pikle do mojej serializacji. Unpickling może uruchomić dowolny kod, a używanie go pickledo przesyłania danych między programami lub przechowywania danych między sesjami jest luką w zabezpieczeniach. JSON nie wprowadza luki w zabezpieczeniach i jest ustandaryzowany, więc do danych mogą mieć dostęp programy w różnych językach, jeśli kiedykolwiek zajdzie taka potrzeba.

Mike Graham
źródło
Dzięki. W każdym razie będę zrzucać i ładować w tym samym programie.
Juanjo Conti
2
Chociaż zagrożenia bezpieczeństwa mogą być niskie w Twojej bieżącej aplikacji, JSON umożliwia całkowite zamknięcie całości.
Mike Graham
4
Można stworzyć wirusa pikle, który trawi się we wszystko, co jest marynowane po załadowaniu. W przypadku json nie jest to możliwe.
Użytkownik
2
Oprócz bezpieczeństwa, JSON ma tę dodatkową zaletę, że ułatwia migracje, więc możesz załadować dane, które zostały zapisane przez starszą wersję aplikacji. W międzyczasie można było dodać pole lub zastąpić całą strukturę podrzędną. Napisanie takiego konwertera (migracji) dla dict / list jest proste, ale z Pickle będziesz miał trudności z załadowaniem go w pierwszej kolejności, zanim będziesz mógł pomyśleć o konwersji.
vog
2
Nie myślałem o tym aspekcie (bezpieczeństwo i zdolność piklowanych obiektów do uruchamiania dowolnego kodu). Dziękuję za zwrócenie uwagi!
CaffeinatedMike
20

Jeśli interesuje Cię przede wszystkim szybkość i przestrzeń, użyj cPickle, ponieważ cPickle jest szybszy niż JSON.

Jeśli bardziej interesuje Cię współdziałanie, bezpieczeństwo i / lub czytelność dla człowieka, użyj formatu JSON.


Wyniki testów, o których mowa w innych odpowiedziach, zostały zarejestrowane w 2010 roku, a zaktualizowane testy z 2016 roku z protokołem 2 cPickle pokazują:

  • cPickle 3,8x szybsze ładowanie
  • cPickle 1,5x szybsze czytanie
  • cPickle nieco mniejsze kodowanie

Odtworzyć to sam z tym sednem , który jest oparty na benchmarku Konstantina, do którego odwołują się inne odpowiedzi, ale używając cPickle z protokołem 2 zamiast pickle i używając json zamiast simplejson (ponieważ json jest szybszy niż simplejson ), np.

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

Wyniki z Pythonem 2.7 na przyzwoitym procesorze 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 z protokołem pickle 3 jest jeszcze szybszy.

JDiMatteo
źródło
11

JSON czy marynata? Co powiesz na JSON i marynatę! Możesz użyć jsonpickle. Jest łatwy w użyciu, a plik na dysku jest czytelny, ponieważ jest to JSON.

http://jsonpickle.github.com/

Paul Hildebrandt
źródło
2
Czy ktoś porównał swoją wydajność z opcjami? Czy wydajność jest porównywalna z surowym jsonem, jak widać tutaj benfrederickson.com/dont-pickle-your-data ?
Josep Valls
To nie jest test porównawczy o szerokim zakresie, ale miałem istniejącą grę, w której zapisywało poziomy za pomocą pikle (python3). Chciałem wypróbować jsonpickle pod kątem czytelności dla ludzi - jednak zapisy poziomów były niestety znacznie wolniejsze. 1597 ms dla jsonpickle i 88 ms lub zwykły pikle przy zapisie poziomu. Dla obciążenia poziomego, 1604 ms dla jsonpickle i 388 ms dla marynaty. Szkoda, bo lubię zapisy czytelne dla ludzi.
Neil McGill
Przetestowałem to w naszym systemie handlowym, czytelność wiąże się z około 2x karą za prędkość serializacji + deserializacji w porównaniu z pikle. Ale świetnie nadaje się do wszystkiego innego.
nurettin
6

Wypróbowałem kilka metod i odkryłem, że użycie cPickle z ustawieniem argumentu protokołu metody zrzutów jako: cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)jest najszybszą metodą zrzutu.

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)

Wynik:

pickle         :   0.847938 seconds
cPickle        :   0.810384 seconds
cPickle highest:   0.004283 seconds
json           :   1.769215 seconds
msgpack        :   0.270886 seconds
Ahmed Abobakr
źródło
4

Osobiście generalnie wolę JSON, ponieważ dane są czytelne dla człowieka . Zdecydowanie, jeśli chcesz serializować coś, czego JSON nie przejmie, użyj marynaty.

Ale w przypadku większości przechowywania danych nie musisz serializować niczego dziwnego, a JSON jest znacznie łatwiejszy i zawsze pozwala otworzyć go w edytorze tekstu i samodzielnie sprawdzić dane.

Szybkość jest niezła, ale w przypadku większości zbiorów danych różnica jest znikoma; Python generalnie i tak nie jest zbyt szybki.

rickcnagy
źródło
1
Prawdziwe. Ale w przypadku 100elementów na liście różnica jest całkowicie nieistotna dla ludzkiego oka. Zdecydowanie inaczej podczas pracy z większymi zbiorami danych.
rickcnagy