2009-01-10 12 views
7

Tengo un intérprete de python incrustado dentro de una aplicación. La aplicación tarda mucho tiempo en arrancar y no tengo la capacidad de reiniciar el intérprete sin reiniciar toda la aplicación. Lo que me gustaría hacer es esencialmente guardar el estado del intérprete y volver a ese estado fácilmente.Reiniciar un intérprete de Python silenciosamente

Comencé almacenando los nombres de todos los módulos en sys.modules con los que el intérprete de Python comenzó y luego eliminé todos los módulos nuevos de sys.modules cuando así lo solicitaba. Esto parece hacer que el intérprete esté preparado para volver a importar los mismos módulos aunque ya los haya importado antes. Sin embargo, esto no parece funcionar en todas las situaciones, como el uso de clases simples y métodos estáticos, etc.

Prefiero no incrustar otro intérprete dentro de este intérprete si puede evitarse, ya que la facilidad de ser capaz de usar las API de aplicaciones se perderá (y también incluirá un pequeño golpe de velocidad, imagino).

Entonces, ¿alguien sabe de una forma en que podría almacenar el estado del intérprete y luego volver a esto para que pueda hacer frente a todas las situaciones?

Gracias,

Dan

Respuesta

4

probar este código a partir de recetas ActiveState: http://code.activestate.com/recipes/572213/

Se extiende salmuera por lo que soporta decapado nada definido en la consola de shell. En teoría sólo debe ser capaz de decapar el módulo principal, de acuerdo con su documentación:

import savestate, pickle, __main__ 
pickle.dump(__main__, open('savestate.pickle', 'wb'), 2) 
+0

Esto se ve prometedor gracias, voy a ver esto con un poco más de profundidad. – Dan

0

Un enfoque propensos poco limpia y fallo podría ser un módulo C que simplemente copia la memoria a un archivo por lo que se pueden cargar de vuelta la próxima vez. Pero dado que no puedo imaginar que esto siempre funcionaría correctamente, ¿el decapado sería una alternativa?

Si puede hacer todos sus módulos seleccionables de lo que debería ser capaz de encurtir todo en globals() para que pueda volver a cargarse.

0

Si conoce de antemano los módulos, las clases, las funciones, las variables, etc. ... en uso, puede guardarlos en disco y volver a cargarlos. No estoy seguro de la mejor manera de abordar el problema si su entorno contiene muchas incógnitas. Sin embargo, puede ser suficiente para recoger pepinos y locales.

1

me gustaría sugerir abordar el problema de causa raíz.

"La aplicación tarda mucho tiempo para puesta en marcha y no tengo capacidad de reiniciar el intérprete sin reiniciar toda la aplicación"

Dudo que esto es en realidad 100% verdad. Si la solicitud general es el resultado de un acto del Congreso, está bien, no se puede cambiar. Pero si la aplicación general fue escrita por personas reales, entonces debería ser posible encontrar y mover el código para reiniciar el intérprete de Python. Es más barato, más simple y más confiable que cualquier cosa que pueda hacer para hackear el problema.

+0

No en este caso, la aplicación es una pieza importante de software lanzada solo una vez al año. Hasta que se introduzca esta funcionalidad, un truco es la única solución disponible para acelerar el desarrollo. – Dan

+1

¡Deseo que mi tiempo haya valido tanto! Esto es algo que tendré que implementar en una o dos horas libres para tratar de hacer mi vida un poco más fácil. Si no funciona bien, seguiremos usando el sistema existente ... – Dan

1

almacenando los nombres de todos los módulos en sys.modules con los que comenzó el intérprete de python y luego eliminando todos los módulos nuevos de sys.módulos cuando sea solicitado. Esto parece hacer que el intérprete esté preparado para volver a importar los mismos módulos aunque ya los haya importado antes.

El enfoque de forzar recarga de módulos puede funcionar en algunas circunstancias, pero es un poco complicado. En resumen:

  • Debe asegurarse de que todos los módulos que tienen dependencias entre sí se vuelven a cargar a la vez. Por lo tanto, cualquier módulo 'x' que haga 'import y' o 'from y import ...' debe ser eliminado de sys.modules al mismo tiempo que el módulo 'y'.

  • Este proceso necesitará protección con un bloqueo si su aplicación o cualquier otro módulo activo está utilizando subprocesos.

  • Cualquier módulo que deje ganchos apuntando a sí mismo en otros módulos no se puede volver a cargar de forma útil, ya que las referencias al antiguo módulo permanecerán en el código no descargado/no descargable. Esto incluye cosas como ganchos de excepción, señales, filtros de advertencias, codificaciones, parches de mono, etc. Si comienzas a cargar alegremente los módulos que contienen el código de otras personas, te sorprenderá la frecuencia con la que hacen cosas así, lo que podría generar errores sutiles y curiosos.

Así que para conseguir que funcione es necesario tener límites bien definidos entre módulos interdependientes - "se importó en el momento de puesta en marcha inicial" probablemente no es bastante lo suficientemente bueno - y para asegurarse de que' están bien encapsulados sin dependencias inesperadas, como parches de mono.

Esto puede basarse en la carpeta, por lo que cualquier elemento en/home/me/myapp/lib podría volver a cargarse como una unidad, dejando otros módulos solos, especialmente el contenido de stdlib en, por ejemplo. /usr/lib/python2.x/ que, en general, no es confiable para volver a cargar. Tengo código para esto en una envoltura de recarga de aplicaciones de webapp todavía no publicada, si es necesario.

Por último:

  • lo que necesita saber un poco sobre el funcionamiento interno de sys.modules, específicamente que deja un montón de valores 'Ninguno' para significar las importaciones en relación fallidos. Si no los elimina al mismo tiempo que elimina los otros valores de su módulo, el intento posterior de importar un módulo puede (a veces) terminar importando 'Ninguno', lo que genera errores confusos.

Este es un detalle de implementación desagradable que podría cambiar y romper su aplicación en una futura versión de Python, pero ese es el precio para jugar con sys.modules de maneras no compatibles.

+0

Creo que el problema con este enfoque es mantener el estado. Un módulo tiene su propio espacio de nombres (al igual que las funciones y clases dentro de él), por lo que cualquier llamada de función podría cambiar ese estado. Incluso el orden de las importaciones podría ser significativo si el módulo ejecutara código en su espacio de nombre global (en importación). –

Cuestiones relacionadas