python - raw - django using database
Necesidad de cursor.close explícito() (5)
La clase de cursor
de Django es solo una envoltura alrededor del cursor
la base de datos subyacente, por lo que el efecto de dejar el cursor
abierto está básicamente vinculado al controlador de la base de datos subyacente.
De acuerdo con las preguntas frecuentes de psycopg2 (psycopg2 es DB driver Django usa para PostgreSQL DB), sus cursores son livianos, pero almacenarán en caché los datos que se devuelven de las consultas realizadas con el objeto del cursor, lo que podría desperdiciar memoria:
Los cursores son objetos ligeros y la creación de muchos de ellos no debería plantear ningún tipo de problema. Pero tenga en cuenta que los cursores utilizados para obtener conjuntos de resultados almacenarán en caché los datos y utilizarán la memoria en proporción al tamaño del conjunto de resultados. Nuestra sugerencia es que casi siempre se cree un nuevo cursor y se desechen los antiguos tan pronto como ya no se requieran los datos (llame a close ()). La única excepción son los bucles estrechos en los que usualmente se usa el mismo cursor para un montón de INSERTOS o ACTUALIZACIONES.
Django usa MySQLdb
como el backend para MySQL, que tiene varios tipos diferentes de cursores, incluidos algunos que realmente almacenan sus conjuntos de resultados en el lado del servidor. La documentación de Cursor.close
para Cursor.close
que es muy importante cerrar los cursores del lado del servidor cuando haya terminado con ellos:
Si está utilizando cursores del lado del servidor, es muy importante cerrar el cursor cuando haya terminado con él y antes de crear uno nuevo.
Sin embargo, esto no es relevante para Django, porque usa la clase de Cursor
predeterminada provista por MySQLdb
, que almacena los resultados en el lado del cliente. Si deja abierto un cursor usado, corre el riesgo de desperdiciar la memoria utilizada por el conjunto de resultados almacenado, al igual que psycopg2
. El método de close
en el cursor simplemente elimina la referencia interna a la conexión db y agota el conjunto de resultados almacenado:
def close(self):
"""Close the cursor. No further queries will be possible."""
if not self.connection: return
while self.nextset(): pass
self.connection = None
Lo mejor que puedo decir al ver su fuente, todos los backends restantes utilizados por Django ( cx_oracle , sqlite3 / pysqlite2 ) siguen el mismo patrón; memoria libre mediante la eliminación / restauración de resultados almacenados / referencias de objetos. Los documentos de sqlite3 ni siquiera mencionan que la clase Cursor
tiene un método de cierre, y solo se usa esporádicamente en el código de ejemplo incluido.
Tiene razón en que un cursor
se cerrará cuando se __del__()
en el objeto del cursor
, por lo que la necesidad de cerrar explícitamente es solo un problema si mantiene una referencia de larga duración al cursor
; por ejemplo, un objeto self.cursor
que mantienes como un método de instancia de una clase.
De vez en cuando, estoy ejecutando consultas en bruto usando connection.cursor()
lugar de usar ORM (ya que definitivamente no es una bala de plata).
He notado que en varios lugares no llamo a cursor.close()
explícito después de que termine con la base de datos. Hasta ahora, esto no ha resultado en ningún error, o problemas de rendimiento. Me pregunto qué tipo de problemas podría tener sin cerrar explícitamente el cursor, ¿qué puede salir mal?
Según tengo entendido, la connection
y el cursor
en Django siguen la "Especificación de la API de la base de datos de Python v2.0" ( PEP-249 ). Y, según él, el cursor
se cerraría automáticamente cada vez que se __del__()
método __del__()
. Supongo que la pregunta podría ser también: ¿Hay un caso de uso cuando no se llama?
Para mi información, estoy usando Python 2.7 y Django 1.6.5.
La llamada explícita de cursor.close()
puede ser por dos razones:
-
__del__
se garantiza que__del__
sea llamado y tiene algunos problemas que puede leer here y here - Explícito es mejor que implícito ( Zen de Python )
Llego un poco tarde a esta pregunta. Tal vez lo que quieres es un ámbito de salida cercano.
from contextlib import closing
from django.db import connection
with closing(connection.cursor()) as cursor:
cursor.execute(...)
cursor.execute(...)
cursor.execute(...)
Mientras que normalmente se puede confiar en el sistema operativo para liberar recursos, siempre es una buena higiene cerrar cosas como las conexiones de la base de datos para garantizar que los recursos se liberen cuando ya no son necesarios, lo realmente importante desde el punto de vista de la base de datos es garantizar que no se produzcan cambios. commit()
ed.
__del__
/ .close()
:
-
__del__
no está garantizado para ser llamado - algunas bases de datos no llaman cursor.close () en su
__del__
(mala práctica, pero verdadera) - algunas bases de datos en realidad no crean conexiones en la función de conexión, pero en su lugar, en la función del cursor (por ejemplo, para 2 y 3: presto de pyhive [quizás ya lo hayan parchado])
En conexiones de servidor en general
La mayoría de los servidores tienen una propiedad de configuración de tiempo de espera inactivo (llamemos a esa T). Si una conexión está inactiva durante más de T segundos, el servidor eliminará la conexión. La mayoría de los servidores también tienen propiedades para establecer el tamaño del grupo de subprocesos de trabajo (W). Si ya tiene conexiones W con su servidor, es probable que se bloquee cuando se intente una nueva conexión. Por un segundo imagina que no tienes la opción de cerrar explícitamente las conexiones. En esa situación, debe establecer que el tiempo de espera sea lo suficientemente pequeño como para que su grupo de trabajadores nunca se utilice completamente, que es una función de la cantidad de conexiones simultáneas que tiene.
Sin embargo, si cierra sus cursores / conexiones (incluso cuando no son equivalentes en [3] arriba, se comportan de manera similar), entonces no tiene que administrar estas propiedades de configuración del servidor y su grupo de hilos simplemente necesita ser grande suficiente para administrar todas las conexiones concurrentes (con la opción de una espera ocasional para nuevos recursos). He visto que algunos servidores (p. Ej., Titan en Cassandra) no se pueden recuperar al quedarse sin trabajadores en el grupo de subprocesos, por lo que todo el servidor se cae hasta que se reinicia.
TL / DR Si está utilizando bibliotecas muy bien desarrolladas, como las que menciona dano
, no tendrá ningún problema. Si está utilizando bibliotecas menos prístinas, puede terminar bloqueando en el servidor adquiriendo un subproceso de trabajo si no llama .close()
, dependiendo de la configuración de su servidor y las tasas de acceso.