Pickle o json?

114

Necesito guardar en el disco un pequeño dictobjeto cuyas claves son del tipo stry los valores son intsy luego recuperarlo . Algo como esto:

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

¿Cuál es la mejor opción y por qué? ¿Serializarlo con pickleo con simplejson?

Estoy usando Python 2.6.

Juanjo Conti
fuente
convertirlo en que? Además, ¿en qué sentido mejor ?
SilentGhost
10
En 2.6 no simplejsonusarías json, usarías el módulo incorporado (que tiene exactamente la misma interfaz).
Mike Graham
5
"mejor"? ¿Mejor para qué? ¿Velocidad? ¿Complejidad? ¿Flexibilidad? ¿Costo?
S.Lott
@Trilarion: YAML es un superconjunto de JSON
Martin Thoma

Respuestas:

68

Si no tiene ningún requisito de interoperabilidad (por ejemplo, solo va a usar los datos con Python) y un formato binario está bien, vaya con cPickle, que le brinda una serialización de objetos Python realmente rápida.

Si desea interoperabilidad o desea un formato de texto para almacenar sus datos, vaya con JSON (o algún otro formato apropiado según sus limitaciones).

Håvard S
fuente
48
JSON parece ser más rápido que cPickle.
mac
5
Mi respuesta destaca las preocupaciones que creo que son más importantes a tener en cuenta al elegir cualquiera de las soluciones. No pretendo que ninguno de los dos sea más rápido que el otro. Si JSON es más rápido Y, por lo demás, adecuado, ¡vaya con JSON! (Es decir, no hay razón para su voto en contra).
Håvard S
10
Mi punto es: no hay una razón real para usar cPickle(o pickle) en función de sus instalaciones a través de JSON. Cuando leí su respuesta por primera vez, pensé que la razón podría haber sido la velocidad, pero como este no es el caso ... :)
mac
14
El punto de referencia citado por @mac solo prueba cadenas. Probé str, int y float por separado y descubrí que json es más lento que cPickle con serialización flotante, pero más rápido con unserialización flotante. Para int (y str), json es más rápido en ambos sentidos. Datos y código: gist.github.com/marians/f1314446b8bf4d34e782
Marian
24
El último protocolo de cPickle ahora es más rápido que JSON. El comentario sobre que JSON es más rápido está desactualizado por algunos años. stackoverflow.com/a/39607169/1007353
JDiMatteo
104

Prefiero JSON sobre pickle para mi serialización. Unpickling puede ejecutar código arbitrario y usarlo picklepara transferir datos entre programas o almacenar datos entre sesiones es un agujero de seguridad. JSON no introduce un agujero de seguridad y está estandarizado, por lo que los programas en diferentes idiomas pueden acceder a los datos si alguna vez lo necesita.

Mike Graham
fuente
Gracias. De todos modos estaré volcando y cargando en el mismo programa.
Juanjo Conti
2
Aunque los riesgos de seguridad pueden ser bajos en su aplicación actual, JSON le permite cerrar todo por completo.
Mike Graham
4
Se puede crear un virus de encurtido que se encurtirá en todo lo que se encurtió después de cargarlo. Con json esto no es posible.
Usuario
2
Además de la seguridad, JSON tiene la ventaja adicional de que facilita las migraciones, por lo que puede cargar datos que fueron guardados por una versión anterior de su aplicación. Mientras tanto, podría haber agregado un campo o reemplazado una subestructura completa. Escribir un convertidor de este tipo (migración) para dict / list es sencillo, pero con Pickle le resultará difícil cargarlo en primer lugar, antes de que pueda pensar en la conversión.
vog
2
No había pensado en este aspecto (la seguridad y la capacidad de los objetos encurtidos para ejecutar código arbitrario). ¡Gracias por señalar eso!
CaffeinatedMike
20

Si lo que más le preocupa es la velocidad y el espacio, use cPickle porque cPickle es más rápido que JSON.

Si está más preocupado por la interoperabilidad, la seguridad y / o la legibilidad humana, utilice JSON.


Los resultados de las pruebas a los que se hace referencia en otras respuestas se registraron en 2010, y las pruebas actualizadas en 2016 con el protocolo cPickle 2 muestran:

  • cPickle carga 3.8 veces más rápida
  • cPickle lectura 1,5 veces más rápida
  • cPickle codificación ligeramente más pequeña

Reproduzca esto usted mismo con esta esencia , que se basa en el punto de referencia de Konstantin al que se hace referencia en otras respuestas, pero usando cPickle con el protocolo 2 en lugar de pickle, y usando json en lugar de simplejson (ya que json es más rápido que simplejson ), por ejemplo

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

Resultados con python 2.7 en un procesador Xeon 2015 decente:

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 con el protocolo pickle 3 es aún más rápido.

JDiMatteo
fuente
11

JSON o pepinillo? ¿Qué tal JSON y pickle? Puede utilizar jsonpickle. Es fácil de usar y el archivo en el disco se puede leer porque es JSON.

http://jsonpickle.github.com/

Paul Hildebrandt
fuente
2
¿Alguien ha comparado su rendimiento con las opciones? ¿Es comparable en rendimiento al json sin procesar como se ve aquí benfrederickson.com/dont-pickle-your-data ?
Josep Valls
Este no es un punto de referencia de amplio alcance, pero tenía un juego existente en el que guardaba los niveles usando pickle (python3). Quería probar jsonpickle para el aspecto legible por humanos; sin embargo, los guardados de nivel fueron, lamentablemente, mucho más lentos. 1597ms para jsonpickle y 88ms o pickle regular en guardado de nivel. Para carga nivelada, 1604ms para jsonpickle y 388 para pickle. Lástima, ya que me gusta la lectura humana salva.
Neil McGill
Probé esto en nuestro sistema comercial, la legibilidad viene con una penalización de velocidad de serialización + deserialización de 2x en comparación con el pickle. Sin embargo, genial para cualquier otra cosa.
nurettin
6

Probé varios métodos y descubrí que usar cPickle con la configuración del argumento de protocolo del método de volcados como: cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)es el método de volcado más rápido.

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)

Salida:

pickle         :   0.847938 seconds
cPickle        :   0.810384 seconds
cPickle highest:   0.004283 seconds
json           :   1.769215 seconds
msgpack        :   0.270886 seconds
Ahmed Abobakr
fuente
4

Personalmente, generalmente prefiero JSON porque los datos son legibles por humanos . Definitivamente, si necesita serializar algo que JSON no aceptará, use pickle.

Pero para la mayoría del almacenamiento de datos, no necesitará serializar nada extraño y JSON es mucho más fácil y siempre le permite abrirlo en un editor de texto y verificar los datos usted mismo.

La velocidad es buena, pero para la mayoría de los conjuntos de datos la diferencia es insignificante; Python generalmente no es demasiado rápido de todos modos.

Rickcnagy
fuente
1
Cierto. Pero para los 100elementos de una lista, la diferencia es completamente insignificante para el ojo humano. Definitivamente diferente cuando se trabaja con conjuntos de datos más grandes.
rickcnagy