2011-01-04 11 views
5

Después de 2 días de depuración, me limité a mi reloj de tiempo: el recolector de basura de Python.
Mi aplicación tiene muchos objetos en la memoria. Y funciona bien
El GC realiza las rondas habituales (no he jugado con los umbrales predeterminados de (700, 10, 10)).
De vez en cuando, en medio de una transacción importante, el barrido de la 2ª generación entra en acción y revisa mis ~ 1.5M de generación de 2 objetos.
¡Esto demora 2 segundos! La transacción nominal toma menos de 0.1 segundos.Django Python Garbage Collection aflicciones

Mi pregunta es ¿qué debo hacer?
Puedo desactivar los barridos de generación 2 (estableciendo un umbral muy alto, ¿es esta la manera correcta?) Y el GC es obediente.
¿Cuándo debería activarlos?
Implementamos un servicio web usando Django, y cada solicitud de usuario toma alrededor de 0.1 segundos.
De manera óptima, ejecutaré estos ciclos de GC gen 2 entre las solicitudes de la API de usuario. ¿Pero cómo hago eso?
Mi vista finaliza con return HttpResponse(), DESPUÉS que me gustaría ejecutar un barrido gen 2 GC.
¿Cómo hago eso? ¿Este enfoque tiene sentido?

¿Puedo marcar el objeto que NUNCA necesita ser recogido como basura para que el GC no los pruebe cada 2º ciclo de gen?
¿Cómo puedo configurar el GC para ejecutar barridos completos cuando el servidor Django está relativamente inactivo?

Python 2.6.6 en múltiples plataformas (Windows/Linux).

+0

"Mi aplicación tiene muchos objetos en la memoria"? ¿Cómo? –

+0

Los contenedores son diccionarios estándar. Los objetos en sí son mis propias instancias de clase (derivadas de un objeto) o tuplas, en las que uno de los elementos es una referencia a dichas instancias de clase (y el resto de los elementos son enteros). –

+0

Dado que los objetos Django Request y Reply son transitorios, ¿cómo se puede mantener algo en la memoria? –

Respuesta

3

Creo que una opción sería la de recolección de basura desactivar por completo y luego manualmente recoge al final de una solicitud como se sugiere aquí: How does the Garbage Collection mechanism work?

Me imagino que usted podría desactivar la GC en su archivo settings.py.

Si desea ejecutar GarbageCollection en cada petición que sugeriría el desarrollo de algunas Middleware que lo hace en el process response método:

import gc 
class GCMiddleware(object): 
    def process_response(self, request, response): 
     gc.collect() 
     return response 
+0

Si bien no implementé esto todavía, parece el enfoque correcto. –

+1

no, este no es el enfoque correcto, recopila GC ANTES de que devuelva la respuesta, por lo que aún impedirá la devolución de la respuesta – dalore

0

Mi punto de vista termina con el regreso HttpResponse(), después de lo cual me gustaría para ejecutar un barrido gen 2 GC.

// turn off GC 
// do stuff 
resp = HttpResponse() 
// turn on GC 
return resp 

no estoy seguro, pero en lugar de //turn on GC que podría ser capaz de // spawn thread to turn on GC in 0.1 sec.

Para asegurarse de que GC no se produzca hasta que se procese la solicitud, si el engendro de la secuencia no funciona, deberá modificar django o utilizar algún tipo de gancho django, como se sugirió dcurtis.

Si está tratando con código de rendimiento crítico, también puede considerar usar un lenguaje de administración de memoria manual como C/C++ para esa parte y usar Python simplemente para invocarlo/consultarlo.

0

Una alternativa podría ser deshabilitar GC por completo, y configurar mod_wsgi (o lo que sea que esté usando) para matar y reiniciar procesos con mayor frecuencia.

1

Hicimos algo como esto para gunicornio. Dependiendo del servidor wsgi que use, debe encontrar los ganchos correctos para DESPUÉS de la respuesta, no antes. Django tiene una señal request_finished, pero esa señal sigue siendo una respuesta.

Para gunicorn, en la configuración es necesario definir los métodos 2, así:

def pre_request(worker, req): 
    # disable gc until end of request 
    gc.disable() 


def post_request(worker, req, environ, resp): 
    # enable gc after a request 
    gc.enable() 

El post_request aquí se ejecuta después de la respuesta HTTP ha sido entregado, por lo que es un muy buen momento para la recolección de basura.