2009-02-17 21 views
11

Es necesario cargar (des-serializar) una lista de pre-computados de números enteros de un archivo en una secuencia de comandos de Python (en una lista de Python). La lista es grande (hasta millones de elementos) y puedo elegir el formato en el que la almaceno, siempre que la carga sea más rápida.lista de Python serialización - método más rápido

¿Cuál es el método más rápido y por qué?

  1. Usando import en un archivo .py que solo contiene la lista asignada a una variable
  2. Usando load
  3. algún otro método cPickle 's (quizás numpy?)

Además, ¿cómo ¿Puede uno comparar tales cosas de manera confiable?

Adición: la medición de esta manera confiable es difícil, porque import se almacena en caché por lo que no se puede ejecutar varias veces en una prueba. La carga con pickle también se vuelve más rápida después de la primera vez probablemente porque el SO precaching de la página. Cargar 1 millón de números con cPickle lleva 1.1 segundos la primera vez que se ejecuta y 0.2 segundos en las ejecuciones posteriores de la secuencia de comandos.

Intuitivamente siento que cPickle debería ser más rápido, pero apreciaría los números (este es un gran desafío para medir, creo).

Y sí, es importante para mí que esto funcione rápidamente.

Gracias

+0

¿Es realmente la parte lenta de su código? ¿Con qué frecuencia vas a cargar el archivo? –

+0

¿Has probado alguno de estos? ¿Qué métricas tienes ahora? –

+0

Por lo que vale, puede evitar problemas de importación utilizando "execfile()" ... – gahooa

Respuesta

7

Conjeturaría cPickle será más rápido si realmente necesita la cosa en una lista.

Si puede utilizar un array, que es un tipo de secuencia integrada, lo cronometré esto en un cuarto de segundo para 1 millón de números enteros:

from array import array 
from datetime import datetime 

def WriteInts(theArray,filename): 
    f = file(filename,"wb") 
    theArray.tofile(f) 
    f.close() 

def ReadInts(filename): 
    d = datetime.utcnow() 
    theArray = array('i') 
    f = file(filename,"rb") 
    try: 
     theArray.fromfile(f,1000000000) 
    except EOFError: 
     pass 
    print "Read %d ints in %s" % (len(theArray),datetime.utcnow() - d) 
    return theArray 

if __name__ == "__main__": 
    a = array('i') 
    a.extend(range(0,1000000)) 
    filename = "a_million_ints.dat" 
    WriteInts(a,filename) 
    r = ReadInts(filename) 
    print "The 5th element is %d" % (r[4]) 
+0

'¿Leer 1000000 ints en 0: 00: 03.500000', y tomó 1/4 segundos para usted? –

+0

sin embargo, tienes razón, array.fromfile es mucho más rápido que cpickle !! –

+0

@eliben - es posible que desee elegir esta como la mejor respuesta. Las lecciones sobre el uso del módulo timeit son populares, ¡pero no responden su pregunta directamente! –

2

"¿cómo puede uno comparar tales cosas de manera confiable?"

No entiendo la pregunta.

Escribe un montón de pequeñas funciones para crear y guardar su lista de varias formas.

Escribe un montón de pequeñas funciones para cargar tus listas en sus diversas formas.

Escribes una pequeña función de temporizador para obtener la hora de inicio, ejecutas el procedimiento de carga varias docenas de veces (para obtener un promedio sólido suficientemente largo para que el ruido de programación del sistema operativo no domine tus mediciones).

Resumir sus datos en un pequeño informe.

¿Qué no es confiable acerca de esto?

Aquí hay algunas preguntas no relacionadas que muestran cómo medir y comparar el rendimiento.

Convert list of ints to one number?

String concatenation vs. string substitution in Python

+0

Estoy de acuerdo. Eso es lo que hago. –

+0

¿Cómo puedo ejecutar "import " varias veces en un bucle si la importación está en caché? –

+1

Si su conjunto de datos es lo suficientemente grande, una medida puede ser todo lo que necesita. Si no, puede ejecutar desde la línea de comando en un bucle de shell y medir el tiempo en su lugar. Además, mira imp.load_module. –

3

Para la evaluación comparativa, ver el módulo timeit en la biblioteca estándar de Python. Para ver cuál es la manera más rápida, implemente todas las formas en que puede pensar y mida con timeit.

Pensamiento aleatorio: dependiendo de lo que esté haciendo exactamente, puede encontrarlo más rápidamente para almacenar "conjuntos de enteros" en el estilo utilizado en .newsrc archivos:

1, 3-1024, 11000-1200000 

Si es necesario comprobar si algo es en ese conjunto, a continuación, cargar y combinar con tal representación debe ser una de las maneras más rápidas. Esto supone que tus conjuntos de enteros son razonablemente densos, con largas secuencias consecutivas de valores adyacentes.

+0

http://docs.python.org/library/timeit.html – Owen

2

Para ayudarle con el tiempo, la biblioteca de Python proporciona el módulo timeit:

Este módulo proporciona una forma sencilla de tiempo pequeños trozos de código Python. Tiene tanto línea de comando como interfaces invocables. Evita una serie de trampas comunes para medir los tiempos de ejecución.

Un ejemplo (en el manual) que compara el costo de usar hasattr()try/except frente a la prueba de falta y el presente objeto atributos:

% timeit.py 'try:' ' str.__nonzero__' 'except AttributeError:' ' pass' 
100000 loops, best of 3: 15.7 usec per loop 
% timeit.py 'if hasattr(str, "__nonzero__"): pass' 
100000 loops, best of 3: 4.26 usec per loop 
% timeit.py 'try:' ' int.__nonzero__' 'except AttributeError:' ' pass' 
1000000 loops, best of 3: 1.43 usec per loop 
% timeit.py 'if hasattr(int, "__nonzero__"): pass' 
100000 loops, best of 3: 2.23 usec per loop 
1

cPickle será el más rápido, ya que se guarda en binario y no se debe analizar ningún código python real.

Otras ventajas son que es más seguro (ya que no ejecuta comandos) y no tiene problemas para configurar $PYTHONPATH correctamente.

2

¿Necesita siempre cargar todo el archivo? De lo contrario, upack_from() podría ser la mejor solución. Supongamos que tiene 1000000 enteros, pero desea cargar solo los de 50000 a 50099, haría:

import struct 
intSize = struct.calcsize('i') #this value would be constant for a given arch 
intFile = open('/your/file.of.integers') 
intTuple5K100 = struct.unpack_from('i'*100,intFile,50000*intSize) 
Cuestiones relacionadas