Pregunta

Tenemos un servidor web basado en Python que unpickles una serie de grandes archivos de datos en el arranque usando cPickle. Los archivos de datos (encurtidos usando HIGHEST_PROTOCOL) son alrededor de 0,4 GB en el disco y cargarse en la memoria como aproximadamente 1,2 GB de Python Objetos - esto toma aproximadamente 20 segundos . Estamos utilizando Python 2.6 en máquinas Windows de 64 bits.

El cuello de botella no es ciertamente el disco (se tarda menos de 0,5 segundos para leer realmente que la cantidad de datos), pero la asignación de memoria y la creación de objetos (hay millones de objetos están creando). Queremos reducir los años 20 para disminuir el tiempo de inicio.

¿Hay alguna manera de deserializar más de 1 GB de objetos en Python mucho más rápido que cPickle (como 5-10x)? Debido a que el tiempo de ejecución está obligado por la asignación de memoria y la creación de objetos, supongo utilizando otra técnica desestibado como JSON no ayudaría aquí.

Sé que algunos lenguajes interpretados tienen una manera de salvar su imagen de memoria entera como un archivo de disco, por lo que pueden cargar de nuevo en la memoria de una sola vez, sin asignación / creación de cada objeto. ¿Hay una manera de hacer esto, o lograr algo similar, en Python?

¿Fue útil?

Solución

  1. Trate el módulo marshal - es interno (utilizado por el byte-compilador) e intencionalmente no se anuncian mucho, pero es mucho más rápido. Nota que no serializar instancias arbitrarias como salmuera, solamente incorporado tipos (no recuerdo las limitaciones exactas, ver documentos). También tenga en cuenta que el formato no es estable.

  2. Si necesita inicializar múltiples procesos y puede tolerar un proceso siempre cargado, no es una solución elegante: cargar los objetos en un solo proceso, y luego no hacer nada en ella, excepto los procesos que se bifurcan bajo demanda. La bifurcación es rápido (copiar al escribir) y comparte la memoria entre todos los procesos. [Aviso legal: no probado; diferencia rubí , el conteo de Python ref activará copias de páginas por lo que este es probablemente inútil si usted tiene enormes objetos y / o acceso a una pequeña fracción de ellos.]

  3. Si los objetos contienen gran cantidad de datos en bruto como matrices numpy, se puede asignar memoria de ellos por mucho más rápida puesta en marcha. PyTables también es bueno para estos escenarios.

  4. Si sólo va a utilizar una pequeña parte de los objetos, a continuación, una base de datos orientado a objetos (como Zope de) puede probablemente le ayudará. Aunque si las necesitan en la memoria, se le acaba de perder una gran cantidad de gastos generales para poca ganancia. (Nunca usado, por lo que este podría ser sin sentido).

  5. Tal vez otras implementaciones Python pueden hacerlo? No sé, sólo un pensamiento ...

Otros consejos

¿Está Load () ing los datos en vinagre directamente desde el archivo? ¿Qué hay de tratar de cargar el archivo en la memoria y luego hacer la carga? Me gustaría empezar con probar el cStringIO (); alternativamente, se puede intentar escribir su propia versión de StringIO que utilizaría memoria intermedia () para cortar la memoria lo que reduciría la copia sea necesario () las operaciones (cStringIO todavía puede ser más rápido, pero tendrá que probar).

A veces hay enormes cuellos de botella de rendimiento al realizar este tipo de operaciones, especialmente en la plataforma de Windows; el sistema Windows es de alguna manera muy optimizadas para hacer un montón de pequeñas lecturas mientras UNIXes sobrellevar bastante bien; si la carga () tiene gran cantidad de pequeños lee o que están llamando a la carga () varias veces para leer los datos, esto ayudaría.

No he utilizado cPickle (o Python), pero en casos como este creo que la mejor estrategia es evitar la carga innecesaria de los objetos hasta que sean realmente necesarias - por ejemplo la carga después de la puesta en marcha de un hilo diferente, en realidad por lo general su mejor evitar innecesaria carga / inicialización en cualquier momento por razones obvias. Google 'carga lenta' o 'inicialización perezosa'. Si realmente necesita todos los objetos que hacer alguna tarea antes de iniciarse el servidor entonces tal vez usted puede tratar de poner en práctica un método de deserialización encargo manual, dicho de otro modo poner en práctica algo por sí mismo si tiene conocimiento íntimo de los datos que se ocupará de que puede ayudar 'exprimir' un mejor rendimiento, entonces el instrumento general para tratar con ella.

¿Usted intentó sacrificar la eficiencia de decapado por no usar HIGHEST_PROTOCOL? No está claro lo que los costes de funcionamiento se asocian con el uso de este protocolo, pero podría valer la pena probar.

imposible responder a esto sin saber más acerca de qué tipo de datos que va a cargar y cómo lo está utilizando.

Si se trata de algún tipo de lógica de negocio, tal vez debería intentar convertirlo en un módulo de pre-compilados;

Si está estructurado de datos, se puede delegar a una base de datos y sólo hay que tirar lo que se necesita?

¿Los datos tienen una estructura regular? ¿Hay alguna manera de dividirla y decidir lo que se requiere y sólo entonces cargarlo?

Voy a añadir otra respuesta que podría ser útil - si se puede, se puede tratar de definir _ ranuras _ en la clase que está más comúnmente creado? Esto puede ser un poco limitante e imposible, sin embargo, parece haber reducido el tiempo necesario para la inicialización en mi examen a aproximadamente la mitad.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top