2011-11-17 11 views
12

considere el siguiente código en mi aplicación webapp2 en Google App Engine:entendimiento persistencia objeto global en Python WSGI aplicaciones

count = 0 

class MyHandler(webapp2.RequestHandler): 

    def get(self): 

     global count 
     count = count + 1 
     print count 

Con cada actualización de la página, los incrementos de recuento superior.

Vengo del mundo PHP, donde cada solicitud era un nuevo entorno global. Lo que entiendo que está sucediendo aquí es que, debido a que estoy usando la configuración de wsgi para WebApp2, Python no inicia un nuevo proceso en cada solicitud. Si yo estaba usando una configuración de CGI, por el contrario, el medio ambiente mundial sería volver a crear una instancia cada vez, como PHP ...

Asumiendo lo anterior es correcto (si no es así, por favor, corríjanme) ...

  1. ¿Cómo podría manejar los escenarios donde quisiera una variable global que persistiera solo durante el tiempo de vida de la solicitud? Podría poner una variable de instancia en la clase RequestHandler, pero ¿qué ocurre con los módulos de utilidad que importo que usan variables globales para cosas como almacenar un objeto de mensaje?
  2. ¿Hay algún tipo de técnica para restablecer todas las variables o forzar una nueva instanciación del entorno?
  3. ¿El entorno global persiste indefinidamente o se restablece en algún momento?
  4. ¿Alguno de estos GAE es específico o la persistencia global de wsgi funciona de la misma forma en cualquier escenario de servidor?

EDIT:

He aquí un intento de utilizar ThreadLocal:

count = 0 

mydata = threading.local() 
mydata.count = 0 

class MyHandler(webapp2.RequestHandler): 

    def get(self): 

     global count 
     count = count + 1 
     print count 

     mydata.count = mydata.count + 1 
     print mydata.count 

Estos también incrementan solicitudes a través de

+0

¿Hay algún motivo específico por el que intente almacenar datos globales fuera del almacén de datos? Parece que lo que estás intentando puede lograrse más fácilmente con un [contador detallado] (http://code.google.com/appengine/articles/sharding_counters.html). –

+0

@ Kevin- esa variable de recuento era solo un ejemplo- mi caso real es algo completamente distinto: solo intento comprender el alcance global dentro del dominio de la aplicación. – Yarin

+0

Relacionados [¿Por qué los pilones usan StackedObjectProxies en lugar de threading.local?] (Http://stackoverflow.com/q/1686768/95735) –

Respuesta

16

Tu conocimiento es el correcto.Si desea que las variables persistan durante el tiempo que dure la solicitud, no debe convertirlas en globales; haga que sean variables de instancia en su clase RequestHandler, a la que se accede como self.var. Como se crea una instancia de un nuevo RequestHandler para cada solicitud, sus variables se mantendrán exactamente el tiempo que lo necesite. Es mejor evitar las variables globales a menos que realmente necesite un alcance global (en lugar de específico de la solicitud).

También tenga en cuenta que su aplicación de App Engine se ejecutará en varios servidores; los globales solo son accesibles a las solicitudes dentro del mismo servidor.

+3

buen punto sobre servidores múltiples- gracias – Yarin

4

Su análisis de la situación es correcta, una aplicación web de Python es una proceso de larga duración. Lleva mucho tiempo activar el intérprete de Python y no se completa cada solicitud.

Es completamente posible crear una variable global que sea diferente "por solicitud". Esto se hace en muchos marcos y a la gente parece gustarle. La forma de hacer esto depende del servidor. La mayoría de los servidores usan "un hilo por solicitud", y creo que GAE también lo hace. Si este es el caso, puede usar un threadlocal variable. Si le preocupa que este valor permanezca entre las solicitudes de ese hilo, necesitará algún código de gestión que pueda engancharse al inicio/finalización de una solicitud. El middleware WSGI es un buen lugar para esto si el framework WebApp2 no proporciona una buena manera de hacerlo.

Es solo Python, y una solicitud se sirve en su propio hilo. Desde allí puedes hacer lo que quieras. No hay nada en Python que simplemente reinicie todas las variables globales, y generalmente no hay garantía (especialmente con GAE) de que el proceso que sirve su solicitud sea el mismo proceso cada vez, lo que significa que sus globales no deberían usarse para persistir datos entre solicitudes a menos que realmente sé lo que estás haciendo.

Existen muchos frameworks que proporcionan una buena compatibilidad para hacer esto, por lo que si WebApp2 no lo hace, sugiero buscar en otro lado. Python tiene muchas opciones y muchas de ellas se ejecutan en GAE.

+0

gracias. ¿Podrían ver mis ediciones? Probé threading.local(), pero ese número aumenta al igual que mi global. ¿Lo estoy implementando bien? – Yarin

+0

Es probable que sus solicitudes estén en el mismo hilo. La mayoría de los servidores WSGI se implementan utilizando un grupo de subprocesos, por lo que no es necesariamente un * nuevo * subproceso por solicitud. No estoy familiarizado con el funcionamiento interno de GAE servidores aplicaciones WSGI tampoco, pero esto es lo que esperaría. –

2

En el caso de su primera pregunta, creo que podría considerar la función webapp2.Request.registry. Es un dict para almacenar instancias que diferentes módulos pueden compartir durante la vida de la solicitud.

Por otro lado, también es útil el webapp2.WSGIApplication.registry. En este caso, las instancias persisten entre las solicitudes y se pueden compartir (y reutilizar) para lo que su aplicación necesite durante la vida de su aplicación, evitando crear instancias en el alcance global.