2010-02-13 11 views
71

Ho bisogno di salvare su disco un piccolo oggetto dict le cui chiavi sono del tipo str e valori sono int s e quindi ripristinarlo. Qualcosa del genere:Pickle o JSON?

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

Qual è l'opzione migliore e perché? Serializzarlo con pickle o con simplejson?

Sto usando Python 2.6.

+0

convertirlo in che cosa? Inoltre, in che senso * migliore *? – SilentGhost

+9

In 2.6 non si userebbe 'simplejson', si userebbe il modulo' json' incorporato (che ha la stessa esatta interfaccia). –

+5

"migliore"? Il meglio per cosa? Velocità? Complessità? Flessibilità? Costo? –

risposta

45

Se non si hanno requisiti di interoperabilità (ad esempio si utilizzano i dati con Python) e un formato binario va bene, andare con cPickle che offre una serializzazione degli oggetti Python veramente veloce.

Se si desidera l'interoperabilità o si desidera che un formato di testo memorizzi i dati, utilizzare JSON (o un altro formato appropriato in base ai propri vincoli).

+30

JSON [sembra essere più veloce] (http://kovshenin.com/archives/ pickle-vs-json-which-is-faster /) rispetto a cPickle. – mac

+3

La mia risposta evidenzia le preoccupazioni che ritengo più importanti da considerare quando si sceglie una soluzione. Non pretendo di essere più veloce dell'altro. Se JSON è più veloce e comunque adatto, vai con JSON! (Ie, non c'è motivo per il tuo voto negativo.) –

+6

Il mio punto è: non c'è un vero motivo per usare 'cPickle' (o' pickle') basato sul tuo locale su JSON. Quando ho letto per la prima volta la tua risposta, ho pensato che la ragione avrebbe potuto essere la velocità, ma poiché non è così ... :) – mac

69

Preferisco JSON su pickle per la mia serializzazione. Unpickling può eseguire codice arbitrario e usare pickle per trasferire dati tra programmi o memorizzare dati tra sessioni è un buco di sicurezza. JSON non introduce un buco di sicurezza ed è standardizzato, quindi è possibile accedere ai dati da programmi in lingue diverse se è necessario.

+0

Grazie. Ad ogni modo scaricherò e caricherò nello stesso programma. –

+1

Sebbene i rischi per la sicurezza potrebbero essere bassi nell'applicazione corrente, JSON consente di chiudere l'intero insieme. –

+3

Si può creare un virus di sottaceto che si raccoglie in tutto ciò che viene decapato dopo il caricamento. Con json questo non è possibile. – User

9

JSON o sottaceto? Che ne dici di JSON e sottaceti! È possibile utilizzare jsonpickle. È facile da usare e il file su disco è leggibile perché è JSON.

http://jsonpickle.github.com/

+2

Qualcuno ha messo a confronto le sue prestazioni rispetto alle opzioni? È paragonabile in termini di prestazioni come json crudo visto qui http://www.benfrederickson.com/dont-pickle-your-data/? –

+0

Questo non è un benchmark ampio, ma avevo un gioco esistente in cui si salvavano i livelli usando pickle (python3). Volevo provare jsonpickle per l'aspetto leggibile dall'uomo, tuttavia i livelli salvati erano purtroppo molto più lenti. 1597ms per jsonpickle e 88ms o pickle normale al livello di salvataggio. Per carico a livello, 1604ms per jsonpickle e 388 per pickle. Peccato perché mi piace il salvabile umano leggibile. –

34

Si potrebbe anche trovare questo interessante, con alcuni grafici per confrontare: http://kovshenin.com/archives/pickle-vs-json-which-is-faster/

+5

Proprio il tipo di confronto che stavo cercando, grazie! – mac

+0

L'articolo confronta le prestazioni solo relative alle stringhe. Ecco uno script che puoi eseguire per testare stringhe, float e inter separatamente: https://gist.github.com/marians/f1314446b8bf4d34e782 – Marian

+3

[In Python 3.4, 'pickle' batte' json' a 'int',' str', e 'float'.] (http://stackoverflow.com/a/26860404/819417) –

4

Personalmente, io in genere preferisco JSON, perché i dati sono leggibile. Sicuramente, se hai bisogno di serializzare qualcosa che JSON non prenderà, piuttosto che usare pickle.

Ma per la maggior parte della memorizzazione dei dati, non è necessario serializzare nulla di strano e JSON è molto più semplice e consente sempre di aprirlo in un editor di testo e controllare i dati da soli.

La velocità è buona, ma per la maggior parte dei set di dati la differenza è trascurabile; Python generalmente non è comunque troppo veloce.

+3

[In Python 3.4,' pickle' è due volte più veloce di 'json'.] (http: // stackoverflow .com/a/26860404/819417) –

+1

Vero. Ma per gli elementi "100" in una lista, la differenza è completamente trascurabile per l'occhio umano. Decisamente diverso quando si lavora con set di dati più grandi. – rickcnagy

10

Se si preoccupano principalmente di velocità e spazio, utilizzare cPickle perché cPickle è più veloce di JSON.

Se si è più interessati all'interoperabilità, alla sicurezza e/o alla leggibilità umana, utilizzare JSON.


I risultati dei test cui si fa riferimento in altre risposte sono state registrate nel 2010, ei test aggiornati nel 2016 con cPickle protocol 2 spettacolo:

  • cPickle 3,8x più veloce di carico
  • cPickle 1.5 volte più veloce la lettura
  • cPickle leggermente la codifica più piccolo

riprodurre da soli con this gist, che si basa sulla Konstantin's benchmark riferimento in altre risposte, ma utilizzando cPickle con protocollo 2 invece di sottaceti, e l'utilizzo di JSON invece di simplejson (dal json è più veloce di simplejson), ad es.

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

risultati con Python 2.7 da un processore decente 2015 Xeon:

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 with pickle protocol 3 is even faster.

0

Ho provato diversi metodi e ha scoperto che l'uso di cPickle con impostando l'argomento protocollo del metodo discariche come: cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL) è il metodo di dumping più veloce.

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) 

uscita:

pickle   : 0.847938 seconds 
cPickle  : 0.810384 seconds 
cPickle highest: 0.004283 seconds 
json   : 1.769215 seconds 
msgpack  : 0.270886 seconds