guardar - Cómo reducir el tiempo necesario para cargar un archivo pickle en python
python pickle ejemplos (3)
He tenido buenos resultados en la lectura de archivos enormes (por ejemplo: ~ 750 MB igraph object - un archivo binario pickle) utilizando cPickle. Esto se logró simplemente envolviendo la llamada de carga de salmuera como se menciona here
Un fragmento de ejemplo en tu caso sería algo como:
import timeit
import cPickle as pickle
import gc
def load_cpickle_gc():
output = open(''myfile3.pkl'', ''rb'')
# disable garbage collector
gc.disable()
mydict = pickle.load(output)
# enable garbage collector again
gc.enable()
output.close()
if __name__ == ''__main__'':
print "cPickle load (with gc workaround): "
t = timeit.Timer(stmt="pickle_wr.load_cpickle_gc()", setup="import pickle_wr")
print t.timeit(1),''/n''
Seguramente, podría haber formas más adecuadas de realizar la tarea, sin embargo, esta solución reduce el tiempo requerido drásticamente. (Para mí, se redujo de 843.04s a 41.28s, alrededor de 20x)
He creado un diccionario en python y me he volcado en pickle. Su tamaño fue de 300MB. Ahora, quiero cargar el mismo pepinillo.
output = open(''myfile.pkl'', ''rb'')
mydict = pickle.load(output)
Cargar este pepinillo lleva alrededor de 15 segundos . ¿Cómo puedo reducir este tiempo?
Especificación de hardware: Ubuntu 14.04, 4 GB de RAM
El siguiente código muestra cuánto tiempo se tarda en volcar o cargar un archivo usando json, pickle, cPickle.
Después del volcado, el tamaño del archivo sería de alrededor de 300MB.
import json, pickle, cPickle
import os, timeit
import json
mydict= {all values to be added}
def dump_json():
output = open(''myfile1.json'', ''wb'')
json.dump(mydict, output)
output.close()
def dump_pickle():
output = open(''myfile2.pkl'', ''wb'')
pickle.dump(mydict, output,protocol=cPickle.HIGHEST_PROTOCOL)
output.close()
def dump_cpickle():
output = open(''myfile3.pkl'', ''wb'')
cPickle.dump(mydict, output,protocol=cPickle.HIGHEST_PROTOCOL)
output.close()
def load_json():
output = open(''myfile1.json'', ''rb'')
mydict = json.load(output)
output.close()
def load_pickle():
output = open(''myfile2.pkl'', ''rb'')
mydict = pickle.load(output)
output.close()
def load_cpickle():
output = open(''myfile3.pkl'', ''rb'')
mydict = pickle.load(output)
output.close()
if __name__ == ''__main__'':
print "Json dump: "
t = timeit.Timer(stmt="pickle_wr.dump_json()", setup="import pickle_wr")
print t.timeit(1),''/n''
print "Pickle dump: "
t = timeit.Timer(stmt="pickle_wr.dump_pickle()", setup="import pickle_wr")
print t.timeit(1),''/n''
print "cPickle dump: "
t = timeit.Timer(stmt="pickle_wr.dump_cpickle()", setup="import pickle_wr")
print t.timeit(1),''/n''
print "Json load: "
t = timeit.Timer(stmt="pickle_wr.load_json()", setup="import pickle_wr")
print t.timeit(1),''/n''
print "pickle load: "
t = timeit.Timer(stmt="pickle_wr.load_pickle()", setup="import pickle_wr")
print t.timeit(1),''/n''
print "cPickle load: "
t = timeit.Timer(stmt="pickle_wr.load_cpickle()", setup="import pickle_wr")
print t.timeit(1),''/n''
Salida:
Json dump:
42.5809804916
Pickle dump:
52.87407804489
cPickle dump:
1.1903790187836
Json load:
12.240660209656
pickle load:
24.48748306274
cPickle load:
24.4888298893
He visto que cPickle toma menos tiempo para volcar y cargar, pero cargar un archivo todavía toma mucho tiempo .
Si está intentando almacenar el diccionario en un solo archivo, es el tiempo de carga para el archivo grande lo que lo está ralentizando. Una de las cosas más fáciles que puede hacer es escribir el diccionario en un directorio en el disco, con cada entrada del diccionario como un archivo individual . Luego, puede hacer que los archivos sean decapados y no seleccionados en varios subprocesos (o mediante multiprocesamiento). Para un diccionario muy grande, esto debería ser mucho más rápido que leer desde y hacia un solo archivo, independientemente del serializador que elija. Hay algunos paquetes como klepto
y joblib
que ya hacen mucho (si no todos los anteriores) por ti. Revisaría esos paquetes. (Nota: soy el autor de klepto
. Consulte https://github.com/uqfoundation/klepto ).
Trate de usar la biblioteca json
lugar de pickle
. Esta debería ser una opción en su caso porque está tratando con un diccionario que es un objeto relativamente simple.
Según este sitio web ,
JSON es 25 veces más rápido en lectura (cargas) y 15 veces más rápido en escritura (volcados).
Consulte también esta pregunta: ¿Qué es más rápido: cargar un objeto de diccionario encurtido o cargar un archivo JSON en un diccionario?
La actualización de Python o el uso del módulo de marshal
con una versión fija de Python también ayuda a aumentar la velocidad ( código adaptado de aquí ):
try: import cPickle
except: import pickle as cPickle
import pickle
import json, marshal, random
from time import time
from hashlib import md5
test_runs = 1000
if __name__ == "__main__":
payload = {
"float": [(random.randrange(0, 99) + random.random()) for i in range(1000)],
"int": [random.randrange(0, 9999) for i in range(1000)],
"str": [md5(str(random.random()).encode(''utf8'')).hexdigest() for i in range(1000)]
}
modules = [json, pickle, cPickle, marshal]
for payload_type in payload:
data = payload[payload_type]
for module in modules:
start = time()
if module.__name__ in [''pickle'', ''cPickle'']:
for i in range(test_runs): serialized = module.dumps(data, protocol=-1)
else:
for i in range(test_runs): serialized = module.dumps(data)
w = time() - start
start = time()
for i in range(test_runs):
unserialized = module.loads(serialized)
r = time() - start
print("%s %s W %.3f R %.3f" % (module.__name__, payload_type, w, r))
Resultados:
C:/Python27/python.exe -u "serialization_benchmark.py"
json int W 0.125 R 0.156
pickle int W 2.808 R 1.139
cPickle int W 0.047 R 0.046
marshal int W 0.016 R 0.031
json float W 1.981 R 0.624
pickle float W 2.607 R 1.092
cPickle float W 0.063 R 0.062
marshal float W 0.047 R 0.031
json str W 0.172 R 0.437
pickle str W 5.149 R 2.309
cPickle str W 0.281 R 0.156
marshal str W 0.109 R 0.047
C:/pypy-1.6/pypy-c -u "serialization_benchmark.py"
json int W 0.515 R 0.452
pickle int W 0.546 R 0.219
cPickle int W 0.577 R 0.171
marshal int W 0.032 R 0.031
json float W 2.390 R 1.341
pickle float W 0.656 R 0.436
cPickle float W 0.593 R 0.406
marshal float W 0.327 R 0.203
json str W 1.141 R 1.186
pickle str W 0.702 R 0.546
cPickle str W 0.828 R 0.562
marshal str W 0.265 R 0.078
c:/Python34/python -u "serialization_benchmark.py"
json int W 0.203 R 0.140
pickle int W 0.047 R 0.062
pickle int W 0.031 R 0.062
marshal int W 0.031 R 0.047
json float W 1.935 R 0.749
pickle float W 0.047 R 0.062
pickle float W 0.047 R 0.062
marshal float W 0.047 R 0.047
json str W 0.281 R 0.187
pickle str W 0.125 R 0.140
pickle str W 0.125 R 0.140
marshal str W 0.094 R 0.078
Python 3.4 utiliza el protocolo 3 de pickle como predeterminado , que no dio ninguna diferencia en comparación con el protocolo 4. Python 2 tiene el protocolo 2 como el protocolo más alto de pickle (seleccionado si se proporciona un valor negativo al volcado), que es dos veces más lento que el protocolo 3.